BootJar + MavenJar. Артефакт не был произведен этой сборкой

У меня есть пример проекта со следующей иерархией:

Sample (root)
   -- model (simple jar)
   -- api   (springboot jar)

Я хочу опубликовать обе сгенерированные банки: обычную банку и загрузочную банку в свой локальный репозиторий.

gradlew clean build -xTest publishToMavenLocal    

Однако возникает следующая ошибка:

* What went wrong:
Execution failed for task ':api:publishMavenJavaPublicationToMavenLocal'.
> Failed to publish publication 'mavenJava' to repository 'mavenLocal'
   > Artifact api.jar wasn't produced by this build.

Корень build.gradle выглядит следующим образом:

plugins {
    id 'java'
    id "org.springframework.boot" version "2.2.5.RELEASE" apply false
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
}
group 'sample'
version '1.0-SNAPSHOT'

apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}
ext {
    artifactVersion = version
    springBootVersion = "2.2.5.RELEASE"
}

allprojects {
    apply plugin: 'java'
    apply plugin: 'idea'
    apply plugin: 'maven'
    tasks.withType(JavaCompile) {
        options.encoding = 'UTF-8'
    }
    repositories {
        mavenCentral()
        jcenter()
    }
}

subprojects {
    apply plugin: "io.spring.dependency-management"
    apply plugin: "maven-publish"

    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8

    dependencyManagement {
        imports {
            mavenBom "org.springframework.boot:spring-boot-dependencies:${springBootVersion}"
        }
    }
    dependencies {
        implementation "org.springframework.boot:spring-boot-dependencies:${springBootVersion}"
    }

    publishing {
        publications {
            mavenJava(MavenPublication) {
                groupId project.group
                artifactId project.name
                version project.version

                from components.java
            }
        }
    }
}

API build.gradle

apply plugin: 'org.springframework.boot'

dependencies {
    compile project(":model")
    implementation "org.springframework.boot:spring-boot-starter-web"
}

bootJar {
}

Добавление задачи bootJava в API build.gradle позволяет публиковать bootJar непосредственно из модуля API, но задача корневой публикации остается неработающей.

publishing {
    publications {
        bootJava(MavenPublication) {
            artifact bootJar
        }
    }
}

Я пробовал почти все решения из документов и Google, но, похоже, ни одно из них не работает. Кто-нибудь может объяснить, что не так настроено?

Версия Gradle: 6.3


person Ermintar    schedule 13.04.2020    source источник
comment
Отлично работает с Gradle 5.3. :-(   -  person Ermintar    schedule 14.04.2020


Ответы (6)


Как указано в документации Gradle здесь:

Начиная с Gradle 6.2, Gradle выполняет проверку работоспособности перед загрузкой, чтобы убедиться, что вы не загружаете устаревшие файлы (файлы, созданные другой сборкой). Это создает проблему с приложениями Spring Boot, которые загружаются с использованием компонента component.java.

Более подробное объяснение доступно по ссылке выше. Они предлагают следующий обходной путь, который я лично пробовал и работал для меня:

настроить исходящие конфигурации

configurations {
       [apiElements, runtimeElements].each {
           it.outgoing.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(jar) }
           it.outgoing.artifact(bootJar)
       }
    }

здесь после конфигурации из моего build.gradle:

....
apply plugin: 'maven-publish'
...

configurations {
    [apiElements, runtimeElements].each {
        it.outgoing.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(jar) }
        it.outgoing.artifact(bootJar)
    }
    ....
}


publishing {
    publications {
        myPublication(MavenPublication) {
            groupId groupId
            artifactId artifactId
            version version
            from components.java
            versionMapping {
                usage('java-api') {
                    fromResolutionOf('runtimeClasspath')
                }
                usage('java-runtime') {
                    fromResolutionResult()
                }
            }
        }
    }
    repositories {
        maven {
            url azureRepoUrl
            name azureRepoName
            credentials {
                username azureRepoUserName
                password azureRepoAccessToken
            }
        }
    }
}
person hasnae    schedule 16.04.2020
comment
Не могли бы вы поделиться дополнительной информацией? Где он размещен? Я получаю сообщение Невозможно преобразовать предоставленную нотацию в объект типа ConfigurablePublishArtifact - person Ermintar; 21.04.2020
comment
Примечание: в многомодульном проекте блок "configurations" должен находиться в модуле с задачей bootjar - person Ermintar; 12.05.2020
comment
Ни одно из решений не работает для задачи bootWar. Есть идеи? - person Tarun; 14.09.2020
comment
Дополнительные строки в configurations {} - это то, что сработало для меня, Gradle v6.5 в моем случае. - person Chris F; 25.01.2021

Отрывок от

Начиная с Gradle 6.2, основная задача jar отключена приложением Spring Boot, и component ожидает ее присутствия. Поскольку задача bootJar по умолчанию использует тот же файл, что и основная задача jar, в предыдущих выпусках Gradle:

  • опубликовать устаревший bootJar артефакт
  • или сбой, если задача bootJar ранее не вызывалась

Простым обходным решением будет настройка исходящих конфигураций. Для многомодульного проекта Gradle поместите приведенную ниже конфигурацию в сервисный модуль (модуль загрузки Spring).


dependencies {
          .....
}

configurations {
    [apiElements, runtimeElements].each {
        it.outgoing.artifacts.removeIf {
            it.buildDependencies.getDependencies(null).contains(jar)
        }
        it.outgoing.artifact(bootJar)
    }
}

Примечание. Нет необходимости что-либо менять в задаче artifactory, если она была настроена правильно. Это рабочее решение было протестировано с помощью Gradle 6.4.1.

Не пробуйте предложенный ими альтернативный вариант, поскольку атрибут classifier устарел в последних версиях, а также изменение задачи bootJar с пользовательской конфигурацией приведет к неправильной конструкции uber jar, и если вы извлечете сгенерированный дистрибутив jar, вы сможете найти отсутствующий каталог BOOT-INF и необходимые значения META-INF/MANIFEST.MF.

jar {
   enabled = true
}

bootJar {
   classifier = 'application'
}

Обновление:

Из Spring Boot 2.5.0 задача jar создает дополнительный архив jar, оканчивающийся на -plain.jar. Это может сломать чью-то сборку, если они использовали некоторые шаблоны, такие как *.jar, для копирования архива сборки, поэтому, чтобы ограничить создание дополнительных jar-файлов, следует использовать следующий фрагмент кода конфигурации задачи jar.

jar {
    enabled = false
}
person Prasanth Rajendran    schedule 29.06.2020

Я мог бы заставить это работать, просто добавив artifact bootJar в задачу публикации, как показано ниже, и без добавления каких-либо конфигураций, как это предлагается в документации Gradle. Я считаю, что это может работать так же, как их первый обходной путь в документации. Протестировано с помощью градиента 6.5.1

publishing {
    publications {
        mavenJava(MavenPublication) {
            artifact bootJar
            artifact sourceJar {
                classifier "sources"
            }
        }
    }
}

project.tasks.publish.dependsOn bootJar
person Jarvis    schedule 24.07.2020

Согласно документации Gradle под,

https://docs.gradle.org/current/userguide/upgrading_version_6.html#publishing_spring_boot_applications

Просто добавьте следующее в файл build.gradle

jar {
   enabled = true
}

bootJar {
   classifier = 'application'
}
person Janitha Madushan    schedule 16.08.2020

Если вы используете gradle kotlin dsl, добавьте эквивалент в свой build.gradle. Это сработало для меня

 configurations {
    val elements = listOf(apiElements, runtimeElements)
    elements.forEach { element ->
        element.get().outgoing.artifacts.removeIf { it -> it.buildDependencies.getDependencies(null).contains(tasks.jar.get())}
        element.get().outgoing.artifact(tasks.bootJar.get())
    }
}
person Sujay Bhowmick    schedule 26.10.2020

Для Spring Boot 2.5.0+ эта конфигурация работает для публикации встроенного jar, его исходников и javadoc:

plugins {
    id 'maven-publish'
    id 'java-library'
}

jar {
    enabled = false
}

java {
    withSourcesJar()
    withJavadocJar()
}

publishing {
    publications {
        publication(MavenPublication) {
            artifact bootJar
            from components.java
        }
    }
}
person codependent    schedule 13.07.2021