【Gradle-13】SNAPSHOT版本检查

1、什么是SNAPSHOT

SNAPSHOT版本是指尚未发布的版本,是一个「动态版本」,它始终指向最新的发布工件(gav),也就是说同一个SNAPSHOT版本可以反复用来发布。
这种情况在大型app多团队的开发中比较常见,比如user模块依赖base模块,因为是在开发阶段,base模块可能会不断的修bug或者提供新能力,这时候就可以不断的发布SNAPSHOT版本提供给user模块使用,而不用发正式版本,也达不到正式版本的要求,而user模块也不用频繁的去改版本就能拉到最新的base代码了。

2、为什么要检测

这种开发效率的提升也带来一定的风险,因为SNAPSHOT版本是开发阶段的动态版本,反复发布具有覆盖的特性,如果在打release包的时候拉到最新的SNAPSHOT版本中有未验证的代码,轻则编译错误,万一带到线上去可是非常危险的。

3、检测思路

SNAPSHOT版本通常用版本号后缀表示:

gradle:classpath('com.github.yechaoa.GradleX:plugin:1.3-SNAPSHOT')maven:<version>1.3-SNAPSHOT</version>
  1. 获取项目中参与编译的所有依赖项;
  2. 校验依赖项的版本号;
    1. 有SNAPSHOT依赖,打印出来,并打断构建流程(可选);
    2. 无 则继续;

听起来并不复杂,实际上也很简单,下面来实战一下。

4、实战

4.1、获取所有依赖

  1. 先获取AppExtension。
AppExtension androidExtension = project.getExtensions().getByType(AppExtension.class);
  • 简单理解它对应的是build.gradle,而build.gradle里面有dependencies{ }
  1. 通过Variants获取Configuration。
androidExtension.getApplicationVariants().all(applicationVariant -> {// debug/release也可以加配置System.out.println(TAG + "applicationVariant.getName() = " + applicationVariant.getName());Configuration configuration = project.getConfigurations().getByName(applicationVariant.getName() + "CompileClasspath");// ...
});
  • 不同的build type它的依赖是有区别的,比如implementation和debugImplementation;
  • 获取Configuration对象是因为依赖项是在配置阶段解析的;

4.2、遍历依赖项

configuration.getResolvedConfiguration().getLenientConfiguration().getAllModuleDependencies().forEach(resolvedDependency -> {ModuleVersionIdentifier identifier = resolvedDependency.getModule().getId();if (isSnapshot(identifier.getVersion())) {snapshotList.add(identifier.getGroup() + ":" + identifier.getName() + ":" + identifier.getVersion());}
});
  • 这里我们要用getResolvedConfiguration()来获取版本决议后的依赖项;
  • 然后通过getLenientConfiguration().getAllModuleDependencies()获取所有依赖,包括依赖中的子依赖;
  • 在遍历中,我们还要获取ModuleVersionIdentifier对象,通过它获取依赖项的坐标GAV;

4.3、Snapshot校验

    private boolean isSnapshot(String version) {String checkRules = "SNAPSHOT";return version.endsWith(checkRules) || version.contains(checkRules);}
  • 校验规则比较简单,就是判断是否包含SNAPSHOT字符串;
  • 符合规则的就添加到集合中,然后打印出来;

4.4、打断编译

    private void blockBuilding() {String errorMassage = "检测到有SNAPSHOT版本依赖";throw new GradleException(errorMassage, new Exception(errorMassage));}

打断编译也比较简单,直接抛个异常就好了。

4.4.1、异常类型

  • GradleException:一般用于在Gradle构建过程中抛出异常,比如自定义Plugin中的逻辑错误等;
  • GradleScriptException:一般表示构建脚本(build script)执行异常,比如语法错误、解析错误等;
  • StopActionException:一般用在Task里面,表示当前Action执行异常,但是还可以继续执行下一个;
  • InvalidUserDataException:这个也是经常遇到和经常用的,一般表示无效的参数或者选项;

更多的可以去翻下源码,一般编译过程中的异常都是继承自RuntimeException

4.5、完整代码

    private void checkSnapshot(Project project, boolean blockSnapshot) {AppExtension androidExtension = project.getExtensions().getByType(AppExtension.class);androidExtension.getApplicationVariants().all(applicationVariant -> {// debug/release也可以加配置System.out.println(TAG + "applicationVariant.getName() = " + applicationVariant.getName());Configuration configuration = project.getConfigurations().getByName(applicationVariant.getName() + "CompileClasspath");List<String> snapshotList = new ArrayList<>();// 所有的依赖,包括依赖中的依赖configuration.getResolvedConfiguration().getLenientConfiguration().getAllModuleDependencies().forEach(resolvedDependency -> {ModuleVersionIdentifier identifier = resolvedDependency.getModule().getId();if (isSnapshot(identifier.getVersion())) {snapshotList.add(identifier.getGroup() + ":" + identifier.getName() + ":" + identifier.getVersion());}});if (snapshotList.size() > 0) {snapshotList.forEach(System.out::println);if (blockSnapshot) {blockBuilding();}} else {System.out.println(TAG + "无SNAPSHOT版本依赖");}});}private void blockBuilding() {String errorMassage = "检测到有SNAPSHOT版本依赖";throw new GradleException(errorMassage, new Exception(errorMassage));}private boolean isSnapshot(String version) {String checkRules = "SNAPSHOT";return version.endsWith(checkRules) || version.contains(checkRules);}

4.6、验证

测试找了一个androidx.core的beta版本,然后把检测规则改成beta来验证。

implementation 'androidx.core:core:1.9.0-beta01'

然后在插件配置中加上Snapshot检查和编译打断(默认关)。

gradleX {checkSnapshot = trueblockSnapshot = true
}

最终效果:
效果.png
是不是还挺简单的~

在实际开发中,如果有CI/CD流程可以添加一个后置执行卡口,再补一个白名单和审批流,如果没有,也可以整个构建报告。

5、最后

如果你不想自己写,这个插件我也发布远端了,按照下面三步走,即可使用。
Step 1. Add the JitPack repository to your build file

repositories {...maven { url 'https://jitpack.io' }
}

Step 2. Add the dependency

dependencies {classpath('com.github.yechaoa.GradleX:plugin:1.5')
}

Step 3. Add the Plugin Id to your build file and configure the gradleX{ } dsl

plugins {id 'com.yechaoa.plugin.gradleX'
}gradleX {printDependencies = falseanalysisSo = truecheckSnapshot = trueblockSnapshot = false
}

ok,以上即是本文介绍内容,学废了吗,快来三连~

6、GitHub

https://github.com/yechaoa/GradleX

7、相关文档

  • 【Gradle-8】Gradle插件开发指南
  • GradleException

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/195606.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

window上Clion配置C++版本的opencv

window上Clion配置opencv 注意版本一定要对的上&#xff0c;否则可能会出错&#xff0c;亲测 widnows 11mingw 8.1.0opencv 4.5.5 mingw8.1下载地址https://sourceforge.net/projects/mingw/ 配置环境变量 cmake下载 安装完添加环境变量 来到官网&#xff0c;下载 windows 对…

基于java web个人财务管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

概念解析 | 网络安全数字孪生(Digital Twin of Cyber Security, DTCS)技术

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:网络安全数字孪生。 概念解析 | 网络安全的“数字镜像” —— 网络安全数字孪生 1. 背景介绍 随着数字化转型进程的深入推进,网络空间安全问题日益凸显。当前的网络安全防护面…

影刀sqlite的插入方法

影刀sqlite的插入方法 变量外面不用加‘’

常见树种(贵州省):002杉类

摘要&#xff1a;本专栏树种介绍图片来源于PPBC中国植物图像库&#xff08;下附网址&#xff09;&#xff0c;本文整理仅做交流学习使用&#xff0c;同时便于查找&#xff0c;如有侵权请联系删除。 图片网址&#xff1a;PPBC中国植物图像库——最大的植物分类图片库 一、杉木 …

「项目阅读系列」go-gin-example star 6.5k!(1)

文章目录 准备工作适宜人群项目信息 项目结构代码阅读主要模块代码主函数模块router 路由模块auth 授权模块数据库 修改文章请求分析其他依赖 总结 准备工作 适宜人群 初学 go 语法&#xff0c;希望了解 go 项目的构建过程和方式。 项目信息 go-gin-example 项目是使用 gin…

integrin + Receptor ; platelet ; Ig-CAM

platelet HPA ; integrin ; Cell adhesion in cancer: Beyond the migration of single cells

ROS参数服务器(Param):通信模型、Hello World与拓展

参数服务器在ROS中主要用于实现不同节点之间的数据共享。 参数服务器相当于是独立于所有节点的一个公共容器&#xff0c;可以将数据存储在该容器中&#xff0c;被不同的节点调用&#xff0c;当然不同的节点也可以往其中存储数据。 使用场景一般存储一些机器人的固有参数&…

大反转!OpenAI董事会辞职,求奥特曼重返OpenAI?「奥特曼24小时流放」大揭秘...

大家好&#xff0c;我是二狗。 想必大家昨天都被Sam Altman被董事会解雇的事情刷屏了。 然而才仅仅过去一天&#xff0c;OpenAI 董事会就反悔了&#xff01;正和Sam Altman 商量让他重返CEO职位。 这一反转和Altman被炒鱿鱼一样突然&#xff0c;凄凄惨惨真真假假真真&#x…

通过汇编理解cortex-m3:第0章

第0章&#xff1a;准备工作 基本想法&#xff1a;利用汇编和gdb调试&#xff0c;来学习cortex-m3汇编指令&#xff0c;以及一些寄存器的功能。 软件和硬件&#xff1a; 硬件&#xff1a;韦东山瑞士军刀中的最小核心板&#xff08;STM32F103C8T6&#xff09; STLINK-V2&#…

Linux线程编程

Linux线程编程初步 一些历史背景 Linux间接起源于Unix&#xff0c;而Linux诞生时并不存在 "线程"的概念。在20世纪90年代线程才流行起来&#xff0c;POSIX Thread标准于 1995年确立。Unix中引入 Thread 之后&#xff0c;大量函数被重写&#xff0c;信号机制也变得复…

Mybatis-Plus《学习笔记 22版尚硅谷 》——感谢【尚硅谷】官方文档

Mybatis-Plus《学习笔记 22版尚硅谷 》 一、MyBatis-Plus1.简介2.特性3.支持数据库4.框架结构5.官方地址 二、入门案例1.开发环境2.建库建表3.创建工程4.配置编码5.测试查询 三、增删改查1.BaseMapper<T>2.调用Mapper层实现CRUD2.1 插入2.2 删除a、根据ID删除数据b、根据…