【问题标题】:Adding gradle task to a subproject in method在方法中将 gradle 任务添加到子项目
【发布时间】:2017-07-06 08:15:02
【问题描述】:

我有一个包含一堆子项目的项目。部分子项目为实用项目,部分项目为实际应用。

“应用程序”子项目都应该生成一个带有给定主类等的 jar 文件。为了解决这个问题,我在父 build.gradle 中添加了以下内容:

def configureApplication(project, mainClass) {
    project.jar { ... }
}

从每个子项目的 build.gradle 中,我调用 configureApplication(project, "my.main.Class")

现在我想向所有应用程序子项目添加一个deploy 任务,以便我可以使用./gradlew deploy 部署所有应用程序。我试图通过将它放在父 build.gradle 中来模仿上述方法:

def configureDeploy(project) {
    project {
        task deploy {
            println "Deploying!"
        }
    }
}

但我正在运行:

Could not find method call() for arguments [build_51pn93...closure3@334ebcaa] on project ':subproj'.

在过去的一个小时里,我尝试了大约一百种其他变体,但都没有成功。

问题:如何在每个子项目的build.gradle中不重复自己的部分子项目添加任务? (另外,在父 build.gradle 中使用方法是实现此目的的合理方法,还是有更 gradle 惯用的方法?)

【问题讨论】:

    标签: gradle build.gradle multi-project


    【解决方案1】:

    在父build.gradle文件中添加子项目的任务确实很常见。

    编辑:每个 cmets,目标是将其应用于所有子项目,而不是选择性的。

    考虑以下settings.gradle

    include 'appA', 'appB', 'utilityC'
    

    这里是根build.gradle。它为每个应用程序定义了一个自定义DeployTask(文档here)(使用subprojects),但没有配置它:

    class DeployTask extends DefaultTask {
        String appName
        String destDir
    
        @TaskAction
        def deploy() {
            if (appName != null && destDir != null) {
                println "deploying ${appName} to ${destDir}"
            }
        }
    }
    
    subprojects { 
        task deploy(type: DeployTask) {}
    }
    

    这里是build.gradle 代表appA

    deploy() {
        appName = "Application A"
        destDir = "~/server/appA"
    }
    

    这里是build.gradle 代表appB

    deploy() {
        appName = "Application B"
        destDir = "~/web/appB"
    }
    

    在这个简单的例子中,utilityC 没有build.gradle

    示例输出:

    $ gradle :appA:deploy 
    deploying Application A to ~/server/appA
    

    $ gradle :appB:deploy 
    deploying Application B to ~/web/appB
    

    $ gradle :utilityC:deploy 
    [no output]
    

    【讨论】:

    • 有趣。我唯一关心的是p.name ==~ /app.*/ 的事情。我没有这样的机制。我非常想通过子项目 build.gradle 将部署任务添加到每个相关的子项目(同时将代码重复降至最低)。
    • 公用事业子项目是否有一个“部署”任务是无操作的?
    • 是的。绝对地。这其实也是我的想法。
    • 我在任务中添加了一个enabled 布尔值,它允许子项目选择加入。即使这也可能被简化(通过在其他字段更新时设置enabled),但恕我直言,这就足够了。
    • Tasks 已经提供了一个enabled 属性,它定义了该任务是否会被跳过。
    【解决方案2】:

    我强烈建议在您的 buildSrc 中使用可配置的参数创建一个自定义的 groovy 类。然后在 gradle 中配置它们。

    class DeployTask extends DefaultTask {
    
        def deploymentName, targets, source, deploymentPlan
    
        @TaskAction
        def deploy() {
           // your stuff using above variables                
        }
    
    }
    

    您可以在主build.gradle 中使用subprojects{} 来指定那里的所有内容,而不是重复自己。

    subprojects { project ->
    
        if (project.name.contains('application1')) {
    
            task deploy (type: package.DeployTask) {
                source          = ""
                deploymentName  = ""
                targettype      = ""
            }
    
        }
    
        if (project.name.contains('application2')) {
    
            task deploy (type: package.DeployTask) {
                source          = ""
                deploymentName  = ""
                targettype      = ""
            }
    
        }
    
    }
    

    或者只是将其添加到项目本身。

    这将遍历settings.gradle中指定的所有子项目,并为每个满足上述条件的子项目创建一个任务部署。


    我看到 @Michael Easter 实际上已经在一个单独的答案中解释了它,我同意我以完全相同的方式将我的应用程序部署到 Weblogic。

    【讨论】:

    • 对。这也让我很震惊。但是,我想将所有子项目特定的配置放在子项目的 bulid.gradle 中。 (就像我使用configureApplication 方法一样。)你知道实现它的方法吗?
    • @aioobe 我很困惑,你说你不想重复自己并添加到子项目而不重复自己,现在你说你想put all subproject specific configuration in the subproject's bulid.gradle我有点迷路了。
    • 好的。对不起。你是对的。我想尽可能少地重复。我想通过在每个可部署子项目的 build.gradle 中编写类似 configureDeploy(project) 的内容来“选择加入”部署任务。之后可以做./gradlew deploy 并且所有具有部署任务的子项目都应该被部署。
    • @aioobe 还有一件事,部署任务是您的任务还是来自插件?
    • 我打算用 here 描述的 ssh 替换我的问题中的 println "Deploying!" 行。
    【解决方案3】:

    我阅读了以前的答案及其cmets,尤其是以下声明:

    我非常希望通过子项目 build.gradle 将部署任务添加到每个相关子项目(同时将代码重复降至最低)。

    这听起来像是插件的完美用例。 Gradle 允许您在buildSrc subproject of your root project 中定义插件。只需将您的插件源代码放在<rootProjectDir>/buildSrc/src/main/groovy。您可以在the docs 中找到更多详细信息。

    您的用例的示例插件可能如下所示:

    class MyDeployPlugin implements Plugin<Project> {
        void apply(Project project) {
            // you can access the project instance this plugin is applied to
            project.task('deploy') {
                // configure your task
            }
        }
    }
    

    现在您可以在您的子项目build.gradle 文件中应用该插件:

    apply plugin: MyDeployPlugin
    
    deploy {
         // configure your task project-specific
    }
    

    最后一条建议:经常使用 Maven 和 Gradle 的人经常说,Gradle 通过脚本编写的灵活性既是最大的优势也是最大的劣势。在 Maven 中,如果要添加或更改功能,通常必须编写插件。在 Gradle 中,您可以简单地编写功能脚本,但如果这种情况经常发生,它会产生集群式和不可重用的代码。因此,每当您需要向多个(子)项目添加相同的功能时,请使用插件。您甚至可以将插件发布到 Maven 或您自己的存储库。

    【讨论】:

    • 我同意当我的一些自定义任务变得太大时,我就是这样做的。很好的解决方案,我没想到!
    • 谢谢!在依赖其他插件(例如Gradle SSH Plugin)方面,我是否有同样的可能性?
    • 取决于哪种方式?您是否需要配置其他插件的任务或扩展,或者您想自己应用它?您可以访问整个项目对象,因此如果您之前应用了 Gradle SSH 插件,您可以像在构建脚本中一样使用它。
    • 好酷!那么我将采用这种方法!谢谢。最后一个问题(出于好​​奇)是否可以从父 build.gradle 中定义的方法向子项目添加任务?
    • 当然是我在示例插件中使用的方法(project.task())。您只需要正确的项目对象,例如通过project(':projectA')。或者,通过project.tasks 获取TaskContainer 并使用其create() 方法之一。
    猜你喜欢
    • 1970-01-01
    • 2018-03-02
    • 2018-03-02
    • 2015-10-12
    • 1970-01-01
    • 2023-01-09
    • 1970-01-01
    • 1970-01-01
    • 2015-07-08
    相关资源
    最近更新 更多