我们使用Ivy进行依赖管理。为了保证稳定性和可跟踪性,我们修复了常春藤文件中所有依赖项的版本号,另外我们使用transitive=false
来避免依赖树不受控制地增长。第二个只有缺点,可能需要一些测试来完成常春藤文件。
由于我们修复了版本号,因此我们无法获得有关更高版本软件包的更新信息。我们不想要的是在构建时获取最新版本的依赖项。 我们想要的是定期检查可用的更新,然后决定是否以及要更新的软件包。
作为一个例子,这是我们从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文件中当前和最新版本包数的报告
答案 0 :(得分:2)
我刚刚找到了一个旨在解决问题的常春藤任务checkdepsupdate:
<target name="resolve" description="Use ivy to resolve classpaths">
<ivy:resolve/>
<ivy:checkdepsupdate showTransitive="false" revisionToCheck="latest.release"/>
</target>
在下面的示例中使用常春藤文件,它会打印以下报告详细说明,第三方依赖项的最新版本。
[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这样的项目故意将他们的可交付成果分成多个罐子以增加灵活性。它允许您只下载您需要的东西,并避免包含一个非常大的单片弹簧罐。
我会建议一些改善常春藤体验的事情
在我的常春藤文件中,我通常只包含包含我正在使用的类的模块,让常春藤处理其他依赖项。我还使用ivy configurations按功能对依赖项进行分组。我的最终目标是使用配置来填充java类路径,因此我的一些依赖项在编译时是必需的,其他的在运行时,最后经常测试需要的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,但在运行时根据类路径中包含的jar确定特定实现。在上面的例子中,我告诉我的构建在运行时使用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>
现在,编译和测试类路径已自动填充,可以作为参考使用:
<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>
解决任务已创建由构建维护的每个类路径的记录。
当您发布到ivy存储库时,您可以指定发布类型。这允许常春藤自动确定特定版本类型的最新发布版本。默认情况下,支持两种类型的发布:
前者对应于Snven版本的Maven概念。在您组织内的另一个团队的控制下构建二进制文件,但尚未准备好发布。后者当然是完全批准和发布的二进制文件,非常适合第三方依赖。
以下是显示两个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>
所以这会实现你的愿望。您的构建将自动注册来自第三方项目的新依赖项。
时间不会停滞不前,也不是项目的依赖树。由于现代Java程序可能具有大量直接依赖性,因此解决依赖关系会变得非常混乱。
但....如何重现旧版本?我们可能会标记我们的源代码,但是如何在那个时间点跟踪的依赖关系。
我决定将每个版本发布到Maven存储库中:
这是一个片段
<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,我需要为我的模块生成Maven POM文件。请注意使用任务deliver和makepom?第一个将创建一个临时常春藤文件,其中包含每个依赖项的已解析版本号。这意味着Maven中生成的POM文件包含我用来构建代码的真实版本。
您可以扩展这个想法,并在发布的二进制文件旁边另外发布以下内容:
在我看来,发布存储库应该是您发布的不变记录和对源代码存储库的重要补充。实际上,在大型企业组织中,这种基于文件的发布记录可能比您的源代码存储库技术(Clearcase - &gt; Subversion - &gt; Git - &gt; ??)更长。