在 Ivy 中检查软件包的最新版本 [英] Check for packages latest version in Ivy

查看:22
本文介绍了在 Ivy 中检查软件包的最新版本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

例如,这是我们截至 2016 年 1 月 14 日的 Spring 依赖项

 <dependency org="org.springframework" name="spring-core" rev="4.2.4.RELEASE" transitionive="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" transitionive="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 文件中包的当前和最新版本号

解决方案

我刚刚发现了一个常春藤任务checkdepsupdate 旨在解决您的问题:

<ivy:resolve/><ivy:checkdepsupdate showTransitive="false" revisionToCheck="latest.release"/></目标>

以我下面示例中的 ivy 文件为例,它会打印以下报告,详细说明我的第 3 方依赖项的最新版本.

[ivy:checkdepsupdate] 可用的依赖更新:[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 以增加灵活性.它允许您只下载您需要的内容,并避免包含一个非常大的整体式弹簧罐.

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

  1. 采用 ivy 对传递依赖项的管理
  2. 使用动态修订
  3. 发布到仓库,以创建发布记录

传递依赖和类路径管理

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

示例常春藤文件:

<信息组织=com.myspotontheweb"模块=演示"/><配置><conf name="compile" description="需要编译应用程序"/><conf name="runtime" description="额外的运行时依赖项" extends="compile"/><conf name="test" description="仅用于测试需要" extends="runtime"/></配置><依赖项><!-- 编译依赖项--><dependency org="org.slf4j" name="slf4j-api" rev="1.7.5" conf="compile->default"/><!-- 运行时依赖--><dependency org="org.slf4j" name="slf4j-log4j12" rev="1.7.5" conf="runtime->default"/><!-- 测试依赖项--><dependency org="junit" name="junit" rev="4.11" conf="test->default"/></依赖项></ivy-module>

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

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

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

<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"/></目标>

编译和测试类路径现在自动填充并准备用作参考:

<mkdir dir="${build.dir}/classes"/><javac srcdir="${src.dir}" destdir="${build.dir}/classes" includeantruntime="false" debug="true" classpathref="compile.path"/></目标><目标名称=测试"依赖=编译"描述=运行单元测试"><mkdir dir="${build.dir}/test-reports"/><junit printsummary="yes"haltonfailure="yes"><类路径><path refid="test.path"/><pathelement path="${build.dir}/classes"/></classpath>....</junit></目标>

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

动态修订

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

  1. 整合
  2. 发布

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

下面举例说明两个动态修订:

<!-- 编译依赖项--><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"/><!-- 运行时依赖--><dependency org="org.slf4j" name="slf4j-log4j12" rev="latest.release" conf="runtime->default"/><!-- 测试依赖项--><dependency org="junit" name="junit" rev="latest.release" conf="test->default"/></依赖项>

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

发布到仓库,以创建发布记录

时间不会静止,项目的依赖树也不会静止.由于现代 Java 程序可能具有大量直接依赖项,因此解析依赖项可能会变得非常混乱.

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

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

这是一个片段

<!-- 可选:包含已解析版本号的中间文件--><ivy:deliver deliverypattern="${build.dir}/ivy.xml" pubrevision="${publish.revision}" status="release"/><!-- 生成 Maven POM --><ivy:makepom ivyfile="${build.dir}/ivy.xml" pomfile="${build.dir}/donaldduck.pom"/></目标><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></目标>

由于我使用的是 Nexus,所以我需要为我的模块生成一个 Maven POM 文件.注意任务 delivermakepom?第一个将创建一个临时 ivy 文件,其中包含我的每个依赖项的已解析版本号.这意味着 Maven 中生成的 POM 文件包含我用于构建代码的真实版本.

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

  • Javadocs jar
  • 源代码jar
  • 常春藤报告罐
  • Junit 报告 jar

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

We use Ivy for dependency management. In order to guarantee stability and traceability, we fix version numbers for all dependencies in our ivy files, plus we use transitive=false to avoid dependency trees to grow uncontrolled. The second has only the disadvantage that it may require a few tests to complete the ivy file.

Since we fix version numbers, we don't get updated about the existence of a later version of a package. What we don't want is to get the freshest version of a dependency at build time. What we want is to periodically check for available updates and later decide whether and which packages to update.

As an example, here are our Spring dependencies as of 01/14/2016

    <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->*"/>

But we have a lot more. So I am asking if there is a smarter way to check for possible updates for all packages (we now have 101 packages).

Ant's ivy:report won't show the availability of a later version. Manually checking 101 packages on Maven is boring.

We also have a local Artifactory installation, I'm saying that if it could prove useful for purpose.

Any idea? What I would like to see is a report with current and latest version numbers of packages in an Ivy file

解决方案

I just found an ivy task checkdepsupdate designed to solve your problem:

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

Taking the ivy file in my example below it prints the following report detailing, the latest releases for my 3rd party dependencies.

[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

I think this might be what you are looking for.


Miscellaneous

At the risk of stating the obvious, by setting transitive=false you take upon yourself the job of managing the entire tree of dependencies. For simple projects that's fine but you're now discovering the downsides of this approach. Projects like Spring have deliberately split their deliverables into multiple jars to increase flexibility. It allows you to only download what you need and avoid the inclusion of one incredibly large monolithic spring jar.

I would recommend a couple of things to improve your ivy experience

  1. Embrace ivy's management of transitive dependencies
  2. Use dynamic revisions
  3. Publish to a repository, in order to create a release record

Transitive dependencies and classpath management

In my ivy file I will generally only include the module that contains the class I'm using, letting ivy take care of the other dependencies. I also use ivy configurations to group dependencies by function. My end goal is to use configurations to populate a java classpath, so some of my dependencies are required at compile time, others at run-time, finally testing frequently requires jars that would never be shipped with the release.

Example ivy file:

<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>

The SLFJ project is an excellent example of how one would use a standard programming API, but at runtime decide on a particular implementation based on the jars included on the classpath. In the above example I tell my build to use the log4j implementation jar at runtime, which will in turn pull down a compatible version of log4j and everything it depends on.

Finally, note how each configuration extends the other? This means that the test configuration will include the jars in both the compile and runtime configurations. Exactly what I'd need when running a unit test using junit.

This is my standard resolve task in 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>

The compile and test classpaths are now auto-populated and ready for use as references:

<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>

And the resolve task has created a record of each classpath maintained by the build.

Dynamic revisions

When you publish to an ivy repository you can specify the release type. This allows ivy to automatically determine the latest published version of a particular release type. By default two types of release are supported:

  1. integration
  2. release

The former corresponds to the Maven concept of Snapshot releases. Built binaries under the control of another team within your organisation, but not ready for release yet. The latter is of course for binaries that are fully approved and released, ideal for 3rd party dependencies.

The following is an example showing the theorical use of the two 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>

So this would achieve your desire. Your build would automatically register new dependencies from 3rd party projects.

Publish to a repository, in order to create a release record

Time does not stand still nor does a project's dependency tree. Due to the high number of direct dependencies a modern Java program may have it can become very confusing to resolve the dependencies.

But.... How does one reproduce an older build? We might tag our source code, but how does one keep track of the dependencies at that point in time.

I decide to publish each release into a Maven repository:

Here's a snippet

<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>

Since I'm using Nexus I need to generate a Maven POM file for my module. Notice the use of the tasks deliver and makepom? The first will create a temp ivy file containing the resolved version numbers of each of my dependencies. This means the resultant POM file in Maven contains the real versions I used to build my code.

You could expand upon this idea and additionally publish the following alongside your released binary:

  • Javadocs jar
  • Source code jar
  • Ivy reports jar
  • Junit reports jar
  • etc

In my opinion the release repository should be the unchanging record for your release and important compliment to the source code repository. Indeed in a large corporate organisation, this kind of file based release record could outlive your source code repository technology (Clearcase -> Subversion -> Git -> ??).

这篇关于在 Ivy 中检查软件包的最新版本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆