利用 Maven 自动化检测 License

利用 Maven 自动化检测 License

继上一篇《开源 License 是什么》,我们来学习如何利用 maven plugin + Jenkins 自动化检测 License,网上相关文章较少,主要参考官网。

一个大型项目会有很多人开发,在引用依赖时很少关注其 License,但在商业产品中,这是非常需要注意的一点,单纯的 GPL License 是不能用于商业产品的。比如我经历的项目中,有 500 多个依赖,如果手动去检测是相当耗时的,如果某个同事突然引用了一个 GPL Liense 的依赖,通过自动化检测,每次发布前运行任务即可发现该问题。

Maven 插件配置

插件名称是:License Maven Plugin

maven 版本要求:3.5.4+

需要执行的 maven 命令:

mvn license:aggregate-add-third-party

在 mvn 命令中,可以通过 -D 参数添加配置,但这样做不方便,直接修改 pom 文件更合适。

在主 pom.xml 文件中,添加如下配置,将对我使用到的配置进行解释,详细的配置可查看官方文档。

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>license-maven-plugin</artifactId>
  <version>2.0.0</version>
  <executions>
    <execution>
      <goals>
        <!-- 该插件有很多种执行目标,比如 license-list 是用来列出可用的 license,add-third-party 用来检测单个项目中的 license -->
        <!-- aggregate-add-third-party 表示检测多模块项目的 license -->
        <goal>aggregate-add-third-party</goal>
      </goals>
    </execution>
  </executions>
  <!-- 设置配置,以下配置都是非必须的 -->
  <configuration>
    <!-- 设置检测结果文件的存放目录 -->
    <outputDirectory>${basedir}/target/generated-sources/license</outputDirectory>
    <!-- 设置检测结果文件,默认是 txt 文件 -->
    <thirdPartyFilename>LICENSE_THIRD_PARTY.csv</thirdPartyFilename>
    <!-- 设置检测结果文件的样式,默认的样式会生成 txt 文件,我觉得不方便查看,在网上找到这么一个 csv 文件的样式,方便在 Excel 中进行分析,使用的是 FreeMarker -->
    <!-- 不熟悉 FreeMarker 的话,还是比较难改样式的,官网只提供了默认的样式,在后文会将该文件内容贴出来 -->
    <fileTemplate>${basedir}/src/license/third-party-file.ftl</fileTemplate>
    <!-- mvn 命令会从不同的 repository 中下载 license 文件,经常会出现请求超时的情况,默认超时时间是 5 秒,将其调整为 10 秒 -->
    <connectionRequestTimeout>10000</connectionRequestTimeout>
    <connectTimeout>10000</connectTimeout>
    <socketTimeout>10000</socketTimeout>
    <!-- 有些依赖可能检测不到 license、mvn 检测出来的 license 有误,或者你需要对某些模块的 license 自己指定,将该配置设置为 true -->
    <!-- 默认配置在 ${basedir}/src/license/THIRD-PARTY.properties 文件中,稍后进行解释 -->
    <useMissingFile>true</useMissingFile>
    <!-- 排除项目中某些 groupId,不对其进行检测,比如自己写的模块,是没必要进行检测的 -->
    <excludedGroups>io\.leo\.test</excludedGroups>
    <!-- 由于不同依赖中使用的 license 名称不同,为了便于自己分类管理,可以将 license 进行合并,比如以下将 Apache 系列的 license 都合并为 The Apache Software License -->
    <licenseMerges>
      <!-- 第一个为合并之后的 license 名称,之后每个 license 以 | 分隔 -->
      <licenseMerge>
        The Apache Software License
        |Apache
        |ASF 2.0
        |Apache v2
        |The Apache Software License, Version 2.0
      </licenseMerge>
      <licenseMerge>
        BSD License
        |BSD
        |BSD-2-Clause
        |The BSD 3-Clause License
      </licenseMerge>
    </licenseMerges>
    <!-- failIfWarning 配合这两个属性使用 <includedLicenses> <excludedLicenses> -->
    <!-- <includedLicenses> 表示白名单,license 一定要在这个列表中 -->
    <!-- <excludedLicenses> 表示黑名单,这个列表中的 license 一定不能出现 -->
    <!-- failIfWarning 设置为 true,表示 license 不在白名单中、或 license 在黑名单中,将会构建失败。结合这个功能,非常方便看出项目中是否有非法 license -->
    <failIfWarning>true</failIfWarning>
  </configuration>
</plugin>

THIRD-PARTY.properties 文件中的内容如下,通过「–」符号连接一个依赖的 groupId、artifactId、version,比如 asm:asm:3.1,对应的 key 就改为 asm–asm–3.1,value 就是手动指定的 license。

asm--asm--3.1=BSD 3 Clause
javax.servlet--servlet-api--2.5=CDDL + GPLv2 with classpath exception
org.json--json--20090211=The JSON License

third-party-file.ftl 内容如下,指定生成结果文件的样式。

<#function licenseFormat licenses>
        <#assign result><#list licenses as license>[${license}]<#if (license_has_next)> - </#if></#list></#assign>
        <#assign result = "\"" + result + "\","/>
    <#return result>
</#function>
<#function artifactFormat p>
    <#if p.name?index_of('Unnamed') > -1>
        <#return "\"" + p.artifactId + "\",\"" + p.groupId + ":" + p.artifactId + ":" + p.version + "\",\"" + (p.url!"no url defined") + "\"">
    <#else>
        <#return "\"" + p.name + "\",\"" + p.groupId + ":" + p.artifactId + ":" + p.version + "\",\"" + (p.url!"no url defined") + "\"">
    </#if>
</#function>
<#if dependencyMap?size == 0>
The project has no dependencies.
<#else>
"License","Name","Artifact","URL"
    <#list dependencyMap as e>
        <#assign project = e.getKey()/>
        <#assign licenses = e.getValue()/>
${licenseFormat(licenses)}${artifactFormat(project)}
    </#list>
</#if>

在 pom 文件中配置好插件之后,执行 mvn license:aggregate-add-third-party 命令,将生成 ${basedir}/target/generated-sources/license/LICENSE_THIRD_PARTY.csv 文件, ${basedir} 为项目主目录。

Jenkins 自动化配置

配置好 pom 文件后,只需要执行 mvn 命令就可以了,所以 Jenkins 上配置自动化也比较简单。

1、添加可用的 maven 版本

image-20200328223308842

image-20200328223356521

image-20200328223418634

新建 Jenkins Job

主要是在 Build 模块添加要执行的 maven 命令,Post-build Action 中将生成的 csv 文件在 Jenkins 上显示出来,可以在 Jenkins 上直接下载,其他项目仓库配置不再细说。

image-20200328223621249

如图,点开某次执行的 job,可以看到生成的 csv 文件。

image-20200328223831846

还有一些命令可以生成静态的 HTML 页面,比较美观,比如 mvn project-info-reports:dependencies,但不如 csv 文件便于分析。

i

发表评论

电子邮件地址不会被公开。 必填项已用*标注