Как плагин может программно настроить публикацию публикации maven-publish и разрешить build.gradle изменять ее

У меня есть общие настройки проекта в плагине, называемом родительским, который пытается применить плагин maven-publish и затем программно настроить расширение публикации. Это похоже на работу, но когда я применяю этот плагин в файле build.gradle script, я не могу настроить расширение публикации, чтобы устанавливать публикации, связанные с проектом.

Я получаю сообщение об ошибке:

  Cannot configure the 'publishing' extension after it has been accessed.

Мое намерение состояло в том, чтобы создать репозиторий публикации в родительском плагине, а затем позволить каждому build.gradle script добавлять соответствующие публикации.

Есть ли способ сделать это?

В настоящее время ParentPlugin.groovy выглядит так:

def void apply(Project project) {
    project.getProject().apply plugin: 'maven-publish'

     def publishingExtension = project.extensions.findByName('publishing')

    publishingExtension.with {
        repositories {
            maven {
                mavenLocal()

                credentials {
                    username getPropertyWithDefault(project.getProject(), 'publishUserName', 'dummy')
                    password getPropertyWithDefault(project.getProject(), 'publishPassword', 'dummy')
                }

            }
        }
    }
}

Мой клиент build.gradle терпит неудачу, когда он пытается настроить расширение публикации.

apply plugin: 'parent'

publishing {
        publications {
            mavenJava(MavenPublication) {
                groupId 'agroup'
                artifactId 'anartifactid'
                version '1.0.0-SNAPSHOT'

                from components.java
            }
        }
}

Возможно ли это? Есть ли другой способ, которым я должен приближаться к этому?

Ответы

Ответ 1

Чтобы справиться с этим, я написал еще один плагин, который может задержать модификации публикации, а также избежать "чтения" расширения, которое поместило бы его в "настроенное" состояние. Плагин называется туманным-издательским плагином, код для "ленивого" блока можно найти в github repo. Это выглядит так:

/**
 * All Maven Publications
 */
def withMavenPublication(Closure withPubClosure) {
    // New publish plugin way to specify artifacts in resulting publication
    def addArtifactClosure = {

        // Wait for our plugin to be applied.
        project.plugins.withType(PublishingPlugin) { PublishingPlugin publishingPlugin ->
            DefaultPublishingExtension publishingExtension = project.getExtensions().getByType(DefaultPublishingExtension)
            publishingExtension.publications.withType(MavenPublication, withPubClosure)
        }
    }

    // It possible that we're running in someone else afterEvaluate, which means we need to run this immediately
    if (project.getState().executed) {
        addArtifactClosure.call()
    } else {
        project.afterEvaluate addArtifactClosure
    }
}

Вы бы тогда назовите его следующим образом:

withMavenPublication { MavenPublication t ->
        def webComponent = project.components.getByName('web')
        // TODO Include deps somehow
        t.from(webComponent)
    }

Плагин доступен в jcenter() как "com.netflix.nebula: туманность-публикация-плагин: 1.9.1".

Ответ 2

ПРИМЕЧАНИЕ относительно репозиториев {} и публикаций {} для плагина maven-publish:

Тема: Как обмануть это недоумение gradle фатальное сообщение об ошибке: Невозможно настроить расширение "публикации" после его доступа

Первое, что нужно попробовать (глубокая магия): (примечание "проект." префикс является необязательным) - Настроить публикации и хранилища не так:

project.publishing {publications {...}}
project.publishing {repositories {...}}

но вместо этого рекомендуется этот стиль:

project.publishing.publications {...}
project.publishing.repositories {...}

Было бы поучительно для гуру gradle объяснить, почему этот трюк работает.

Еще одно известное решение - убедиться, что каждое приложение плагина maven-publish находится в том же блоке кода проекта, что и project.publishing.repositories и project.publishing.publications. Но это сложнее и сложнее, чем первое, что нужно попробовать, поскольку по умолчанию CBF применяет maven-publish и второе применение может сама вызвать ту же ошибку. maven-publish обычно применяется в pub/scripts/publish-maven.gradle, если PUB_PUBLISH_MAVEN не будет переопределять это местоположение файла, в этом случае вызывающий должен применять плагин maven-publish. См. https://orareview.us.oracle.com/29516818, как это неприемлемо обходное решение может быть выполнено (для проектных emcapms) при использовании CBF.

P.S. Когда-нибудь я напишу это с минимальными примерами кода. Но сейчас я помещаю это трудно завоеванное знание, чтобы спасти других людей от траты времени на эту общую проблему публикации в maven.

Ответ 3

Немного поздно, но я нашел решение, для которого не требуется дополнительный плагин: (Это было взято из одного из моих внутренних плагинов, который может работать со старыми и новыми публикациями, таким образом... withType... stuff.

вместо:

    project.plugins.withType(MavenPublishPlugin) {
        project.publishsing {
            publications {
                myPub(MavenPublication) {
                    artifact myJar
                }
            }
        }
    }

сделайте следующее:

    project.plugins.withType(MavenPublishPlugin) {
        project.extensions.configure PublishingExtension, new ClosureBackedAction( {
            publications {
                myPub(MavenPublication) {
                    artifact myJar
                }
            }
        })
    }

Это не приведет к немедленному разрешению расширения, но будет применяться конфигурация в момент его первого разрешения кем-либо. Конечно, было бы совершенно разумно использовать этот стиль конфигурации в вашем плагине для всего проекта, чтобы настроить репозитории и использовать расширение публикации в сценариях сборки, как обычно. Это позволило бы избежать путаницы для авторов buildscript.