根据Wikipedia的说法 , monorepo是一种软件开发策略,其中许多项目存储在同一存储库中。 这种策略可以快速检测到因依赖关系的更改而导致的潜在问题和破坏,并且已被许多使用大型代码库的组织采用,例如Google,Facebook和Twitter。
如果碰巧将Gradle用作首选的构建工具,那么您也可以应用此策略,这要归功于3.1版中引入的Composite Builds功能(在撰写本文时,最新版本为5.0)。 让我们看一下不使用此功能时的典型monorepo工作流程。
没有复合建筑的生活
假设您刚刚在一家公司中工作,该公司的项目保存在单个存储库中。 每个项目都有一个单独的构建,并且它们之间的唯一关系是通过相互依赖来满足它们的需要。 有些项目比其他项目具有更多的依赖关系,有些项目甚至可能与其他项目没有依赖关系。
项目数量很重要; 当价格较低时,您可以说所有这些工具都可以放在一个伞项目下,就像使用Maven及其反应堆功能所做的那样。 Gradle具有类似的功能,除了在不触发所有其他项目的情况下更轻松地定位特定的构建之外。 可以这样说,Gradle的反应堆更智能,可以选择要执行的目标。
但是,当项目数量超过一打,比如说几百个时,会发生什么? 即使使用更智能的反应堆,Gradle也必须阅读所有项目的配置,然后解决适当的目标。 这肯定会花费您宝贵的日常工作时间,这是很大的禁忌。
解决方案是将每个项目分解为单独的版本。 反应堆功能已经一去不复返了,因此我们不必付出阅读和配置所有项目的代价,以后再丢弃其中的大多数项目。 但是,现在当依赖项可能引入了错误或二进制不兼容时,我们失去了做出反应的机会,这是在monorepo中组织代码的原因之一。
现在,我们必须遵循以前尝试过的
- 在依赖项项目上进行更改。
- 构建工件并将其发布到存储库。 大多数人都依赖快照工件。
- 确保从属项目消耗了新发布的工件/快照。
- 编译并运行测试以确定代码是否可以再次运行。
- 冲洗并重复直到起作用。
这种方法的问题在于,我们浪费时间来发布中间工件,并且不时地形成表单,我们会忘记发布快照发行版,而在调试会话中花费数小时,直到我们意识到二进制文件不正确,呃。
复合材料为营救
现在让我们看看Composite Builds如何解决我们所遇到的问题。我们首先查看以下项目及其之间的依赖关系
项目1
Project2 <–取决于— Project1
Project3 <–取决于— Project2
这个小的依存关系图告诉我们,对Project1所做的任何更改都会影响Project2,进而影响到Project3,因为对Project2所做的更改也会影响Project3。 此monorepo的目录结构如下所示
.
├── project1
│ └── build.gradle
├── project2
│ └── build.gradle
└── project3
└── build.gradle
在这里,我们可以看到三个项目及其各自的构建文件。 每个项目都有其自己的发布生命周期和版本,我们可以在其构建文件中观察到
project1 / build.gradle
apply plugin: 'java'
group = 'com.acme'
version = '1.0.0'
project2 / build.gradle
apply plugin: 'java'
group = 'com.acme'
version = '2.3.0'
dependencies {
compile 'com.acme:project1:1.0.0'
}
project3 / build.gradle
apply plugin: 'java'
group = 'com.acme'
version = '1.2.0'
dependencies {
compile 'com.acme:project2:2.3.0'
}
激活“复合构建”功能需要在名为settings.gradle
的文件中配置项目之间的链接。 项目2和3需要此文件,因此我们的存储库如下所示
.
├── project1
│ └── build.gradle
├── project2
│ ├── build.gradle
│ └── settings.gradle
└── project3
├── build.gradle
└── settings.gradle
接下来,我们像这样写下项目之间的链接
project2 / settings.gradle
includeBuild '../project1'
project3 / settings.gradle
includeBuild '../project2'
大。 完成此设置后,我们现在可以通过发出以下命令来构建project3
$ cd project3
$ pwd
/tmp/project3
$ gradle classes
> Task :processResources
> Task :project2:processResources
> Task :project1:compileJava
> Task :project1:processResources
> Task :project1:classes
> Task :project1:jar
> Task :project2:compileJava
> Task :project2:classes
> Task :project2:jar
> Task :compileJava
> Task :classes
如您所见,project1和project2均已构建。 对project1进行更改并再次触发对project3的构建,将按预期构建所有三个项目。 现在,假设将此Monorepo扩展到数十个或数百个项目,您将很快意识到几乎不需要快照版本(如果有)。 Gradle还具有其他功能,例如输入/输出的任务缓存,这也使构建更快。 同样,最近宣布的构建缓存功能通过“捕获” CI服务器场中其他节点计算的输出来加快构建速度。
如果您喜欢本文,则可以在我的博客上找到有关Gradle和构建工具的其他有趣文章。
翻译自: https://www.javacodegeeks.com/2018/12/building-monorepo-projects-gradle.html