在 Ivy 中检查包的最新版本

Check for packages latest version in Ivy

我们使用 Ivy 进行依赖管理。为了保证稳定性和可追溯性,我们在 ivy 文件中修复了所有依赖项的版本号,另外我们使用 transitive=false 来避免依赖树不受控制地增长。第二种唯一的缺点是可能需要进行一些测试才能完成 ivy 文件。

由于我们修复了版本号,因此我们不会获得关于是否存在更高版本软件包的更新。我们不希望 是在构建时获取依赖项的最新版本。 我们想要的是定期检查可用的更新,然后决定是否更新以及更新哪些包。

例如,这是截至 2016 年 1 月 14 日的 Spring 依赖关系

    <dependency org="org.springframework"               name="spring-core"                      rev="4.2.4.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework"               name="spring-aop"                       rev="4.2.4.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework"               name="spring-beans"                     rev="4.2.4.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework"               name="spring-context"                   rev="4.2.4.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework"               name="spring-context-support"           rev="4.2.4.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework"               name="spring-expression"                rev="4.2.4.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework"               name="spring-jdbc"                      rev="4.2.4.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework"               name="spring-orm"                       rev="4.2.4.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework"               name="spring-tx"                        rev="4.2.4.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework"               name="spring-web"                       rev="4.2.4.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework"               name="spring-webmvc"                    rev="4.2.4.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework"               name="spring-test"                      rev="4.2.4.RELEASE"     transitive="false"          conf="test->*"/>
    <dependency org="org.springframework.plugin"        name="spring-plugin-core"               rev="1.2.0.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework.plugin"        name="spring-plugin-metadata"           rev="1.2.0.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework.batch"         name="spring-batch-core"                rev="3.0.6.RELEASE"     transitive="false"          conf="runtime->*"/>
    <dependency org="org.springframework.batch"         name="spring-batch-infrastructure"      rev="3.0.6.RELEASE"     transitive="false"          conf="runtime->*"/>

但我们还有更多。所以我问是否有更智能的方法来检查所有包的可能更新(我们现在有 101 个包)。

Ant 的 ivy:report 不会显示更新版本的可用性。在 Maven 上手动检查 101 个包很无聊。

我们还有一个本地 Artifactory 安装,我是说如果它能被证明有用的话。

有什么想法吗?我想看到的是一份包含 Ivy 文件中包的当前和最新版本号的报告

我刚找到一个 ivy 任务 checkdepsupdate 旨在解决您的问题:

<target name="resolve" description="Use ivy to resolve classpaths">
    <ivy:resolve/>
    <ivy:checkdepsupdate showTransitive="false" revisionToCheck="latest.release"/>
</target>

在我下面的示例中使用 ivy 文件,它会打印以下报告详细信息,即我的第 3 方依赖项的最新版本。

[ivy:checkdepsupdate] Dependencies updates available :
[ivy:checkdepsupdate]   org.slf4j#slf4j-api 1.7.5 -> 1.7.13
[ivy:checkdepsupdate]   org.slf4j#slf4j-log4j12 1.7.5 -> 1.7.13
[ivy:checkdepsupdate]   junit#junit 4.11 -> 4.12

我想这可能就是您要找的。


杂项

冒着陈述显而易见的风险,通过设置 transitive=false,您自己承担了管理整个依赖关系树的工作。对于简单的项目,这很好,但您现在发现了这种方法的缺点。 Spring 等项目故意将其可交付成果分成多个 jar 以增加灵活性。它允许您只下载所需的内容,并避免包含一个非常大的整体 spring jar。

我会推荐一些东西来改善你的常春藤体验

  1. 采用 ivy 的传递依赖管理
  2. 使用dynamic revisions
  3. 发布到存储库,以创建发布记录

传递依赖和class路径管理

在我的 ivy 文件中,我通常只包含包含我正在使用的 class 的模块,让 ivy 处理其他依赖项。我还使用 ivy configurations 按功能对依赖项进行分组。我的最终目标是使用配置来填充 java class 路径,因此我的一些依赖项在编译时需要,其他在 run-time,最后经常测试需要永远不会的 jar随版本发布。

常春藤文件示例:

<ivy-module version="2.0">
    <info organisation="com.myspotontheweb" module="demo"/>

    <configurations>
        <conf name="compile" description="Required to compile application"/>
        <conf name="runtime" description="Additional run-time dependencies" extends="compile"/>
        <conf name="test"    description="Required for test only" extends="runtime"/>
    </configurations>

    <dependencies>
        <!-- compile dependencies -->
        <dependency org="org.slf4j" name="slf4j-api" rev="1.7.5" conf="compile->default"/>

        <!-- runtime dependencies -->
        <dependency org="org.slf4j" name="slf4j-log4j12" rev="1.7.5" conf="runtime->default"/>

        <!-- test dependencies -->
        <dependency org="junit" name="junit" rev="4.11" conf="test->default"/>
    </dependencies>

</ivy-module>

SLFJ 项目是一个很好的例子,说明了如何使用标准编程 API,但在运行时根据 class 中包含的 jars 决定特定的实现小路。在上面的示例中,我告诉我的构建在运行时使用 log4j 实现 jar,这将依次下载兼容版本的 log4j 及其依赖的所有内容。

最后,请注意每个配置如何扩展另一个配置?这意味着测试配置将在编译和运行时配置中包含 jar。当 运行 使用 junit 进行单元测试时,这正是我所需要的。

这是我在 ANT 中的标准解决任务:

<target name="resolve" depends="install-ivy" description="Use ivy to resolve classpaths">
    <ivy:resolve/>

    <ivy:report todir='${build.dir}/ivy-reports' graph='false' xml='false'/>

    <ivy:cachepath pathid="compile.path" conf="compile"/>
    <ivy:cachepath pathid="test.path"    conf="test"/>
</target>

编译和测试 class 路径现在 auto-populated 可以用作参考:

<target name="compile" depends="resolve" description="Compile code">
    <mkdir dir="${build.dir}/classes"/>
    <javac srcdir="${src.dir}" destdir="${build.dir}/classes" includeantruntime="false" debug="true" classpathref="compile.path"/>
</target>

<target name="test" depends="compile" description="Run unit tests">
    <mkdir dir="${build.dir}/test-reports"/>
    <junit printsummary="yes" haltonfailure="yes">
        <classpath>
            <path refid="test.path"/>
            <pathelement path="${build.dir}/classes"/>
        </classpath>
        ..
        ..
    </junit>
</target>

并且解析任务已经为构建维护的每个class路径创建了一个记录。

动态修订

当您发布到 ivy 存储库时,您可以指定发布类型。这允许 ivy 自动确定特定发布类型的最新发布版本。默认支持两种版本:

  1. 整合
  2. 发布

前者对应Snapshot发布的Maven概念。在您组织内的另一个团队的控制下构建二进制文件,但尚未准备好发布。后者当然适用于完全批准和发布的二进制文件,非常适合第 3 方依赖项。

下面举例说明两者的理论用法dynamic revisions:

<dependencies>
    <!-- compile dependencies -->
    <dependency org="myorg" name="teamA" rev="latest.integration" conf="compile->default"/>
    <dependency org="myorg" name="teamB" rev="latest.integration" conf="compile->default"/>
    <dependency org="myorg" name="teamC" rev="latest.integration" conf="compile->default"/>
    <dependency org="org.slf4j" name="slf4j-api" rev="latest.release" conf="compile->default"/>

    <!-- runtime dependencies -->
    <dependency org="org.slf4j" name="slf4j-log4j12" rev="latest.release" conf="runtime->default"/>

    <!-- test dependencies -->
    <dependency org="junit" name="junit" rev="latest.release" conf="test->default"/>
</dependencies>

这样就可以实现你的愿望了。您的构建将自动注册来自 3rd 方项目的新依赖项。

发布到存储库,以创建发布记录

时间不会停滞不前,项目的依赖树也不会停滞不前。由于大量的直接依赖关系,现代 Java 程序可能会在解决依赖关系时变得非常混乱。

但是....如何重现旧版本?我们可能会标记我们的源代码,但是如何在那个时间点.

跟踪依赖关系

我决定将每个版本发布到 Maven 存储库中:

  • how to publish 3rdparty artifacts with ivy and nexus

这是一个片段

<target name="prepare" description="Generate POM">
    <!-- Optional: Intermediate file containing resolved version numbers -->
    <ivy:deliver deliverpattern="${build.dir}/ivy.xml" pubrevision="${publish.revision}" status="release"/>

    <!-- Generate the Maven POM -->
    <ivy:makepom ivyfile="${build.dir}/ivy.xml" pomfile="${build.dir}/donaldduck.pom"/>
</target>

<target name="publish" depends="init,prepare" description="Upload to Nexus">
    <ivy:publish resolver="nexus-deploy" pubrevision="${publish.revision}" overwrite="true" publishivy="false" >
        <artifacts pattern="${build.dir}/[artifact](-[classifier]).[ext]"/>
    </ivy:publish>
</target>

因为我正在使用 Nexus I need to generate a Maven POM file for my module. Notice the use of the tasks deliver and makepom?第一个将创建一个临时 ivy 文件,其中包含我的每个依赖项的已解析版本号。这意味着 Maven 中生成的 POM 文件包含我用来构建代码的真实版本。

您可以扩展这个想法,并在您发布的二进制文件旁边另外发布以下内容:

  • Java文档 jar
  • 源代码jar
  • Ivy 报告 jar
  • Junit 报告 jar
  • 等等

在我看来,release repository 应该是你发布的不变记录,也是对源代码库的重要补充。事实上,在大型企业组织中,这种基于文件的发布记录可能比您的源代码存储库技术更长久(Clearcase -> Subversion -> Git -> ??)。