英文:
How to write Gradle plugin to cut down build.gradle file
问题
以下是您提供的文本的翻译部分:
A bit of Context first:
首先一些背景信息:
I am working on migrating my companies projects to be built by Gradle.
我正在进行将我的公司的项目迁移到使用Gradle构建的工作。
One thing, that this results in, is having redundancy in my build.gradle files,
其中的一个结果是,在我的build.gradle文件中存在冗余,
as I am configuring the same Skeleton over and over again.
因为我一遍又一遍地配置相同的框架。
This includes:
这包括:
- Setting the java-,maven-publish- and org.sonarcube-plugin
- 设置java,maven-publish和org.sonarcube-plugin
- Configuring the repositories to be mavenCentral and our private Artifactory Repo
- 配置存储库为mavenCentral和我们的私有Artifactory Repo
- Configuring the publishing block, that is all the same, except for the artifactId
- 配置发布块,除了artifactId之外都相同
- Building a Manifest inside the Jar block (using helper Methods, to correctly build the Manifests classpath)
- 在Jar块内构建清单(使用辅助方法来正确构建清单的类路径)
- Helper Methods
- 辅助方法
- two Tasks
- 两个任务
- two dependsOn statements
- 两个dependsOn语句
build.gradle file as of now:
截止目前的build.gradle文件:
(接下来是代码部分,无需翻译)
what I want to achieve:
我想要实现的目标:
(接下来是代码部分,无需翻译)
Most of the values are the same.
大多数值都是相同的。
The ones that aren't are passed in via Environment-Variables (Jenkins-JobName,...),
那些不同的值是通过环境变量传递的(例如Jenkins-JobName,...),
or get determined through helper Methods.
或者通过辅助方法确定。
I reckon, that I will most likely not end up with a buildfile like the one above,
我估计,最终我不太可能得到像上面那样的构建文件,
but at least some of the buildfile must be outsourceable.
但至少有些构建文件必须可以外包。
I know as of now, that I can create separate Tasks in a plugin, like comparing two files, that have been passed. What I didn't find a solution to yet:
截止目前,我知道我可以在插件中创建单独的任务,比如比较传递的两个文件。但我还没有找到解决方案的问题:
- Can I modify the Jar Task of the project applying the plugin, inside the plugin?
- 我可以在插件内部修改应用插件的项目的Jar任务吗?
- How do I pass Outputs from other Tasks into my plugin's tasks?
- 如何将其他任务的输出传递给我的插件任务?
- How do I access the applying project's data (i.e. the runtimeClasspath)
- 如何访问应用项目的数据(例如runtimeClasspath)
- Is a plugin even what I want to do, or is there another way of cutting down the build.gradle file?
- 插件甚至是否是我想要做的事情,或者还有其他方式来简化build.gradle文件?
I am relatively unexperienced with Gradle. I have read through quite a bit of the docs and other postings, but chances are I just overlooked some best-practice way of doing certain things. Therefore, feel free to criticize my build file as well as my approach!
我对Gradle相对不熟悉。我已经阅读了相当多的文档和其他帖子,但很可能我只是忽视了某些最佳实践方法。因此,随时批评我的构建文件以及我的方法!
英文:
A bit of Context first:
I am working on migrating my companies projects to be built by Gradle.
One thing, that this results in, is having redundancy in my build.gradle files,
as I am configuring the same Skeleton over and over again.
This includes:
- Setting the java-,maven-publish- and org.sonarcube-plugin
- Configuring the repositories to be mavenCentral and our private Artifactory Repo
- Configuring the publishing block, that is all the same, except for the artifactId
- Building a Manifest inside the Jar block (using helper Methods, to correctly build the Manifests classpath)
- Helper Methods
- two Tasks
- two dependsOn statements
build.gradle file as of now:
plugins {
id 'io.spring.dependency-management' version '1.0.12.RELEASE'
id "org.sonarqube" version "3.2.0"
id 'maven-publish'
id 'java'
}
group = 'group'
version = 'version'
sourceCompatibility = '11'
ext.artifactName = 'ProjectName'
// Where to look for dependencies:
repositories {
mavenCentral()
maven{
credentials{
username = "${artifactory_user}"
password = "${artifactory_password}"
}
url "${artifactory_contextUrl}"
allowInsecureProtocol = true
}
}
// Where to publish what Artifacts to:
publishing {
publications {
maven(MavenPublication) {
groupId = 'group'
artifactId = 'ProjectName'
String buildEnvVar = System.env.BUILDENVIRONMENT
if(buildEnvVar == null){
version = 'LOCAL BUILD'
}else{
version = 'version'
}
from components.java
}
}
repositories {
maven {
// change to point to your repo, e.g. http://my.org/repo
name = "gradle-dev"
url = "${artifactory_contextUrl}"
allowInsecureProtocol = true
credentials{
username = "${artifactory_user}"
password = "${artifactory_password}"
}
}
}
}
dependencies {...}
jar {
// configuration of variables
String dateString = new Date().format("yyyy-MM-dd HH:mm:ss ")
String localBuild = "LOCAL BUILD by " + System.getProperty("user.name") + " on " + dateString
String buildEnvVar = System.env.BUILDENVIRONMENT
String buildEnvironment
String classpath = createCP()
if(buildEnvVar == null){
buildEnvironment = localBuild
archiveName = "ProjectName"
}else{
buildEnvironment = buildEnvVar
archiveFileName= "ProjectName_" + version + ".jar"
delete fileTree("build/libs") {
include('*')
}
}
manifest {
attributes (
"Main-Class": "org.example.foo",
"Specification-Title" : "ProjectName",
"Specification-Vendor" : "blab",
"Specification-Version" : "Spec-version",
"Implementation-Title" : "$System.env.JOB_NAME",
"Implementation-Version" : "Impl-version",
"Implementation-Vendor" : "blub",
"Implementation-Vendor-Id" : "blob",
"Implementation-Url" : "bleb",
"Build-By" : buildEnvironment,
'Class-Path': classpath
)
}
}
String createCP () {
// super secret can't share
}
// will suffix the jars with release or debug, depending on it being compiled with or without debug-information
project.gradle.taskGraph.whenReady{
boolean isDebug = project.gradle.taskGraph.getAllTasks().join(' ').contains('debugJar')
compileJava.options.debug = isDebug
String suffix = isDebug? "debug" : "release"
String fullJarName = "$artifactName-$suffix" + ".jar"
jar.setProperty('archiveName', fullJarName)
}
tasks.named('test') {
useJUnitPlatform()
}
task debugJar() {}
debugJar.dependsOn(jar)
//Downloads all Jars the project depends on, and saves them in buildDirectory/output/libs if the gradle build command is executed.
task copyToLib(type: Copy) {
into "${buildDir}/output/libs"
from configurations.runtimeClasspath
}
build.dependsOn(copyToLib)
what I want to achive:
plugins {
id 'io.spring.dependency-management' version '1.0.12.RELEASE'
id "org.sonarqube" version "3.2.0"
id 'maven-publish'
id 'java'
id 'mySuperPlugin'
}
// Configure mySuperPlugin
mySuperPlugin {
artifactId = 'xyz'
mainClass = 'org.example.foo'
version = 'version'
stuffFromOtherTasks = ...
}
// Where to look for dependencies:
repositories {
mavenCentral()
maven{
credentials{
username = "${artifactory_user}"
password = "${artifactory_password}"
}
url "${artifactory_contextUrl}"
allowInsecureProtocol = true
}
}
dependencies {...}
Most of the values are the same.
The ones that aren't are passed in via Environment-Variables (Jenkins-JobName,...),
or get determined through helper Methods.
I reckon, that i will most likely not end up with a buildfile like the one above,
but atleast some of the buildfile must be outsourceable.
I know as of now, that i can create seperate Tasks in a plugin, like comparing two files, that have been passed. What I didn't find a solution to yet:
- Can I modify the Jar Task of the project applying the plugin, inside the plugin?
- How do I pass Outputs from other Tasks into my plugins tasks?
- How do I access the applying projects data (i.e. the runtimeClasspath)
- Is a plugin even what i want to do, or is there another way of cutting down the build.gradle file?
I am relatively unexperienced with gradle. I have read through quite a bit of the docs and other postings, but chances are i just overlooked some best-practice way of doing certain things.
Therefore, feel free to criticize my buildfile aswell as my approach!
答案1
得分: 0
您可以以几种方式完成这个任务。这取决于您的项目是否由多个子项目组成,或者它们是独立的项目。对于独立的项目,您可以在您的settings.gradle
文件中执行以下操作:
includeBuild("../common-project/build.gradle")
通用项目将只包含通用的build.gradle
文件,并且您可以在其中声明要共享的所有项目。它看起来像一个普通的build.gradle
文件。
这将要求每个项目共享另一个项目的通用配置,但不需要检出任何额外的项目,只需检出通用项目和项目本身。有关更多详情,请参见:
https://docs.gradle.org/current/userguide/composite_builds.html
如果您有更多的多项目构建,比如由多个微服务或子项目组成的较大项目,那么可以使用多项目设置,并在根build.gradle
中的allprojects
闭包中声明通用部分:
allprojects {
plugin: java
plugin: web
repositories {
....
}
dependencies {
....
}
}
在多项目的情况下,您需要检出顶层项目和所有子项目。您的文件夹布局可能如下所示:
- my-project
- service-1
src
build.gradle
- service-2
src
build.gradle
- service-3
src
build.gradle
build.gradle
settings.gradle
在多项目设置中,service1、service2 和 service3 将在 settings.gradle
文件中使用 include
进行声明,如下所示:
rootProject.name = 'my-project'
include 'service1'
include 'service2'
include 'service3'
在多项目设置中,通常将其存储在单个源代码仓库中,而不是使用includeBuild
,其中每个项目将属于单独的源代码仓库。前一种方式会强制您在多项目的情况下检出适当数量的项目。但在includeBuild
的情况下,开发人员必须知道要检出至少 2 个项目。
英文:
You can do this in a couple of ways. And this comes down to if your project is composed of multiple sub-projects or if they are stand alone projects. For stand alone projects you can do the following in your settings.gradle file:
includeBuild("../common-project/build.gradle")
The common project would just house the common build.gradle
file, and you'd declare all of the items you want to share in there. It would look like a normal build.gradle file.
That would require that each project share the common configuration from another project, but wouldn't require any additional projects be checked out. Just the common project and the project itself. For more details see:
https://docs.gradle.org/current/userguide/composite_builds.html
If you have more of a multi-project build like say many micro-services or subprojects that make up a larger project then using multi-project setup and declare the common pieces in the allprojects
closure in the root build.gradle:
allprojects {
plugin: java
plugin: web
repositories {
....
}
dependencies {
....
}
}
In the multi-project case you'd have to check out the top level project and all subprojects. Your folder layout might look like this:
- my-project
- service-1
src
build.gradle
- service-2
src
build.gradle
- service-3
src
build.gradle
build.gradle
settings.gradle
In the multi-project setup service1, service2, and service3 would be declared in the settings.gradle
file using include
like so:
rootProject.name = 'my-project'
include `service1`
include `service2`
include `service3`
In a multi-project setup you'd typically house that in a single source repository as oppose to using includeBuild
where each project would belong to a separate source code repo. The former way forces you to checkout the appropriate number of projects in the multi-project case. But, in the includeBuild
case the developer would have to know to check out minimum of 2 projects.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论