【Gradle-13】SNAPSHOT版本检查

59 篇文章 0 订阅
本文介绍了在大型应用开发中如何使用SNAPSHOT版本提高开发效率,以及为何需要检测SNAPSHOT依赖以防止编译错误。作者提供了Gradle插件实现依赖版本检测的方法,并给出了在实际项目中的应用示例和使用步骤。
摘要由CSDN通过智能技术生成

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. 校验依赖项的版本号;

    • 有SNAPSHOT依赖,打印出来,并打断构建流程(可选);

    • 无 则继续。

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

4、实战

4.1、获取所有依赖

  1. 先获取AppExtension。
AppExtension androidExtension = project.getExtensions().getByType(AppExtension.class);

简单理解它对应的是build.gradle,而build.gradle里面有dependencies{ };

    2. 通过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
}

最终效果:

是不是还挺简单的~

在实际开发中,如果有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
}

6、GitHub

github.com/yechaoa/Gra…

7、相关文档

作者:yechaoa
链接:https://juejin.cn/post/7292416512333840438
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值