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

為{幸葍}努か 提交于 2020-01-15 10:03:16

问题


I want to create a maven publication from inside a RuleSource that will be published via the maven-publish plugin. The artifacts of the publication are the outputs from a series of Zip tasks that are created from rules. When I try to add the artifacts, I get a circular rule exception.

Here is my very simple 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'
}

The testpub plugin exists in the buildSrc directory. To be able to apply it as above, it requires the following properties file:

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

Here is the very simple plugin file:

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)
                        }
                    }       
                }        
            }
        }
    }
}

The plugin creates a number of tasks called someTaskx where x=[0..4]. They simply zip up the src directory. I want to add the output files as artifacts to the single MavenPublication. However, I get the following exception:

* 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

What is wrong and how do I fix it?


回答1:


I don't fully understand why is this a "cycle", but the rule methods always have one mutable part (the subject) and zero or more immutable (the inputs). In your second method, you are passing the publishing as the subject you want to change and the tasks as the input. I thought that would be ok, but obviously it isn't.

You might have tried to switch the method arguments, pass the tasks first and then the PublishingExtension, but you would likely not be able to change it (as gradle docs say it's immutable).

I am not sure what exactly is your use case and there might be an easier solution that doesn't use the rules, or plugin at all. Maybe you could ask another question with the original requirement instead of this specific problem.

But back to your issue. The solution to your problem might be something like this:

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)
            }
        }
    }
}

The hack here is to run the mutator of the tasks first (@Defaults phase should run before @Mutate) and save the tasks, so we don't need to ask for them later. Rules can include static final fields, so we use a list here.

Then we run the publication enhancer. The code you have used won't work. It works in the config part, but not in the groovy class. So I have prepared the publication and then just added the artifacts from the buffer.

I ran gradlew publish and got:

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

So it seems it's working.



来源:https://stackoverflow.com/questions/41911241/gradle-how-to-make-rule-created-ziptask-as-maven-publication-artifact

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!