Gradle: 如何将规则创建的 ZipTask 作为 maven 发布工件

Gradle: how to make rule-created ZipTask as maven publication artifact

我想从将通过 maven-publish 插件发布的 RuleSource 内部创建一个 Maven 发布。发布的工件是根据规则创建的一系列 Zip 任务的输出。当我尝试添加工件时,出现循环规则异常。

这是我的非常简单的build.gradle:

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '3.3'
}

apply plugin: 'groovy'
apply plugin: 'testpub'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.4.7'
}

testpub 插件存在于 buildSrc 目录中。为了能够像上面那样应用它,它需要以下属性文件:

// buildSrc/src/main/resources/META_INF/gradle-plugins/testpub.properties
implementation-class=TestPubPlugin

这是非常简单的插件文件:

import org.gradle.api.Project
import org.gradle.api.Plugin
import org.gradle.model.RuleSource
import org.gradle.api.Task
import org.gradle.model.Mutate
import org.gradle.model.Finalize
import org.gradle.api.tasks.bundling.Zip
import org.gradle.model.ModelMap
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication


class TestPubPlugin implements Plugin<Project> {
    void apply(Project project) {    
        project.configure(project) {
            apply plugin: 'maven-publish'

            publishing {
                repositories {
                    maven {
                        url "someUrl"
                    }
                }
            }

        }
    }

    static class TestPubPluginRules extends RuleSource {

        @Mutate
        public void createSomeTasks(final ModelMap<Task> tasks) {
            5.times { suffix ->
                tasks.create("someTask${suffix}", Zip) {
                    from "src"
                    destinationDir(new File("build"))
                    baseName "someZip${suffix}"
                }
            }
        }

        @Mutate
        public void configurePublishingPublications(final PublishingExtension publishing, final ModelMap<Task> tasks) {    

            // Intention is to create a single publication whose artifacts are formed by the `someTaskx` tasks
            // where x = [0..4]
            publishing {
                publications {
                    mavPub(MavenPublication) {
                        tasks.matching {it.name.startsWith('someTask')}.each { task ->
                            artifact(task)
                        }
                    }       
                }        
            }
        }
    }
}

该插件创建了许多名为 someTaskx 的任务,其中 x=[0..4]。他们只是简单地压缩 src 目录。我想将输出文件作为工件添加到单个 MavenPublication。但是,我收到以下异常:

* What went wrong:
A problem occurred configuring root project 'testpub'.
> A cycle has been detected in model rule dependencies. References forming the cycle:
  tasks
  \- TestPubPlugin.TestPubPluginRules#createSomeTasks(ModelMap<Task>)
     \- MavenPublishPlugin.Rules#realizePublishingTasks(ModelMap<Task>, PublishingExtension, File)
        \- PublishingPlugin.Rules#tasksDependOnProjectPublicationRegistry(ModelMap<Task>, ProjectPublicationRegistry)
           \- projectPublicationRegistry
              \- PublishingPlugin.Rules#addConfiguredPublicationsToProjectPublicationRegistry(ProjectPublicationRegistry, PublishingExtension, ProjectIdentifier)
                 \- publishing
                    \- TestPubPlugin.TestPubPluginRules#configurePublishingPublications(PublishingExtension, ModelMap<Task>)
                       \- tasks

出了什么问题,我该如何解决?

我不完全理解为什么这是 "cycle",但规则方法总是有一个可变部分(主题)和零个或多个不可变部分(输入)。在第二种方法中,您将 publishing 作为要更改的主题传递,并将 tasks 作为输入传递。我以为这样就可以了,但显然不是。

您可能尝试过切换方法参数,先传递任务然后传递 PublishingExtension,但您可能无法更改它(因为 gradle 文档说它是不可变的) .

我不确定您的用例到底是什么,可能有一个更简单的解决方案,它根本不使用规则或插件。也许你可以用原始需求问另一个问题而不是这个特定问题。

但是回到你的问题。您的问题的解决方案可能是这样的:

import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.bundling.Zip
import org.gradle.model.Defaults
import org.gradle.model.ModelMap
import org.gradle.model.Mutate
import org.gradle.model.RuleSource

class TestPubPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.configure(project) {
            apply plugin: 'maven-publish'

            publishing {
                publications {
                    maven(MavenPublication) {
                        groupId 'com.example'
                        artifactId 'artifact'
                    }
                }
                repositories {
                    maven {
                        url "someUrl"
                    }
                }
            }

        }
    }

    static class TestPubPluginRules extends RuleSource {
        static final def buffer = []

        @Defaults
        public void createSomeTasks(final ModelMap<Task> tasks) {
            5.times { suffix ->
                tasks.create("someTask${suffix}", Zip) {
                    from "src"
                    destinationDir(new File("build"))
                    baseName "someZip${suffix}"
                }
            }
            tasks.each { task ->
                if (task.name.startsWith('someTask'))
                    buffer << task
            }
        }

        @Mutate
        public void configurePublishingPublications(PublishingExtension extension) {
            MavenPublication p = extension.publications[0]
            buffer.each { task ->
                p.artifact(task)
            }
        }
    }
}

这里的 hack 是首先 运行 任务的修改器(@Defaults 阶段应该 运行 在 @Mutate 之前)并保存任务,所以我们不需要请求它们之后。规则可以包含静态最终字段,所以我们在这里使用列表。

然后我们 运行 发布增强器。您使用的代码将不起作用。它适用于配置部分,但不适用于 groovy class。所以我准备了出版物,然后从缓冲区中添加了工件。

我运行gradlew publish得到:

Execution failed for task ':publishMavenPublicationToMavenRepository'.
> Failed to publish publication 'maven' to repository 'maven'
   > Invalid publication 'maven': artifact file does not exist: 'build\someZip0.zip' 

所以它似乎有效。