【Gradle-13】SNAPSHOT版本检查

news2024/9/25 4:38:51

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 = true
    blockSnapshot = 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 = false
    analysisSo = true
    checkSnapshot = true
    blockSnapshot = false
}

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

6、GitHub

https://github.com/yechaoa/GradleX

7、相关文档

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux系统化学习】进程的状态 | 僵尸进程 | 孤儿进程

个人主页点击直达&#xff1a;小白不是程序媛 Linux专栏&#xff1a;Linux系统化学习 目录 操作系统进程的状态 运行状态 阻塞状态 进程阻塞的现象 挂起阻塞状态 Linux进程状态 Linux内核源代码怎么说 R&#xff08;running状态&#xff09;运行状态 S&#xff08;sl…

关于DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC的一些发现

任务在哪 这个是11g以后的自动收集统计信息的后台任务&#xff0c;10g之前是在dba_scheduler_jobs里查看 SQL> SELECT CLIENT_NAME ,STATUS ,MEAN_INCOMING_TASKS_7_DAYS,MEAN_INCOMING_TASKS_30_DAYS FROM DBA_AUTOTASK_CLIENT WHERE…

云课五分钟-0Cg++默认版本和升级-std=c++17

前篇&#xff1a; 云课五分钟-0B快速排序C示例代码-注释和编译指令 视频&#xff1a; 云课五分钟-0Cg默认版本和升级-stdc17 文本&#xff1a; 在Linux系统中&#xff0c;可以通过以下步骤升级g&#xff1a; 打开终端&#xff0c;使用root权限或者sudo权限登录。输入以下命令…

[AI]ChatGPT4 与 ChatGPT3.5 区别有多大

ChatGPT 3.5 注册已经不需要手机了&#xff0c;直接邮箱认证就可以&#xff0c;这可真算是好消息&#xff0c;坏消息是 ChatGPT 4 还是要收费。 那么 GPT-3.5 与 GPT-4 区别有多大呢&#xff0c;下面简单测试一下。 以从 TDengine 订阅数据为例&#xff0c;TDengine 算是不太小…

【C++】一文全解C++中的异常:标准库异常体系&自定义异常体系(含代码演示)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一.C语言传统的处理错误的方式二.C异常…

python-opencv 培训课程笔记(1)

python-opencv 培训课程笔记&#xff08;1&#xff09; 博主参加了一次opencv库的培训课程&#xff0c;把课程所学整理成笔记&#xff0c;供大家学习&#xff0c;第一次课程包括如下内容&#xff1a; 1.读取图像 2.保存图像 3.使用opencv库显示图像 4.读取图像为灰度图像 …

每天一道算法题(六)——返回一组数字中所有和为 0 且不重复的三元组

文章目录 前言1、问题2、示例3、解决方法4、效果5、注意点 前言 注意&#xff1a;答案中不可以包含重复的三元组。 1、问题 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] n…

基于PHP+MySql的酒店信息管理系统的设计与实现

一、系统开发环境 运行环境&#xff1a;phpstudy或者wampserver&#xff0c; 开发工具&#xff1a;vscodephpstorm 数据库&#xff1a;mysql 二、酒店管理系统功能 1.前台功能&#xff1a; 首页客房推荐&#xff0c;周边特色介绍 酒店在线预订 订单查询&#xff0c;可以…

linux中利用fork复制进程,printf隐藏的缓冲区,写时拷贝技术,进程的逻辑地址与物理地址

1.prinf隐藏的缓冲区 1.思考:为什么会有缓冲区的存在? 2.演示及思考? 1).演示缓存区没有存在感 那为什么我们感觉不到缓冲区的存在呢?我们要打印东西直接就打印了呢? 我们用代码演示一下: 比如打开一个main.c,输入内容如下: #include <stdio.h>int main(){printf…

【机器学习】划分训练集和测试集的方法

在机器学习中&#xff0c;我们的模型建立完成后&#xff0c;通常要根据评估指标来对模型进行评估&#xff0c;以此来判断模型的可用性。而评估指标主要的目的是让模型在未知数据上的预测能力最好。因此&#xff0c;我们在模型训练之前&#xff0c;要对训练集和测试集进行划分。…

python-opencv 培训课程笔记(2)

python-opencv 培训课程笔记&#xff08;2&#xff09; 1.图像格式转换 先看一下cvtColor函数的例子 #默认加载彩图 pathrD:\learn\photo\cv\cat.jpg# imread(path,way) #way0 灰度图。way1 彩图 #默认彩图 imgcv2.imread(path) img_dogcv2.imread(path_dog) #图片格式的转化…

Lesson 04 模板入门

C&#xff1a;渴望力量吗&#xff0c;少年&#xff1f; 文章目录 一、泛型编程1. 引入2. 函数模板&#xff08;1&#xff09;函数模板概念&#xff08;2&#xff09;函数模板格式&#xff08;3&#xff09;函数模板的原理&#xff08;4&#xff09;函数模板的实例化&#xff08…

git rebase 和 git merge的区别?以及你对它们的理解?

文章目录 前言是什么分析区别后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;git操作相关 &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&#xff0c;感谢…

MVSNet论文笔记

MVSNet论文笔记 摘要1 引言2 相关基础2.1 多视图立体视觉重建&#xff08;MVS Reconstruction&#xff09;2.2 基于学习的立体视觉&#xff08;Learned Stereo&#xff09;2.3 基于学习的多视图的立体视觉&#xff08;Learned MVS&#xff09; Yao, Y., Luo, Z., Li, S., Fang,…

阿坤老师的独特瓷器(Java详解)

一、题目描述 示例&#xff1a; 输入&#xff1a; 5 3 4 5 6 2 5 3 7 6 5 输出&#xff1a; 3 二、题解 思路分析&#xff1a; 题目要求我们计算出“独特瓷器”的个数&#xff0c;而“独特瓷器”是指对于瓷器A&#xff0c;没有另一个瓷器B&#xff0c;直径和高度都大于A。则…

系列三、双亲委派 沙箱安全 机制

一、概述 当一个类收到了类加载的请求&#xff0c;它首先不会尝试自己去加载这个类&#xff0c;而是把这个请求委派给父类去完成&#xff0c;每一层的类加载器都是如此&#xff0c;因此所有的请求最终都应该传送到启动类加载器中&#xff0c;只有当父类加载器反馈自己无法完成…

算法通关村——数字中的统计、溢出、进制转换处理模板

数字与数学基础问题 1、数字统计 1.1、符号统计 LeetCode1822. 给定一个数组&#xff0c;求所有元素的乘积的符号&#xff0c;如果最终答案是负的返回-1&#xff0c;如果最终答案是正的返回1&#xff0c;如果答案是0返回0. 这题其实只用看数组中0和负数的个数就好了&#x…

基于卡尔曼滤波实现行人目标跟踪

目录 1. 作者介绍2. 目标跟踪算法介绍2.1 目标跟踪背景2.2 目标跟踪任务分类2.3 目标跟踪遇到的问题2.4 目标跟踪方法 3. 卡尔曼滤波的目标跟踪算法介绍3.1 所用数据视频说明3.2 卡尔曼滤波3.3 单目标跟踪算法3.3.1 IOU匹配算法3.3.2 卡尔曼滤波的使用方法 3.4 多目标跟踪算法 …

【顺序表的实现】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 1. 数据结构相关概念 1、什么是数据结构 2、为什么需要数据结构&#xff1f; 2、顺序表 1、顺序表的概念及结构 1.1 线性表 2、顺序表分类 3、动态顺序表的实现 总…

高效管理文件:如何通过文件数量归类提高工作效率

在日常生活和工作中&#xff0c;需要处理大量的文件和资料。然而&#xff0c;如果这些文件没有得到妥善的管理&#xff0c;就会使得我们花费大量的时间和精力去寻找和整理它们。对于大量文件&#xff0c;按照数量归类可以使得文件管理更加有序和规范。根据文件的数量建立相应的…