Определите артефакт, который будет использоваться в качестве зависимости в другом проекте.

TL;DR

Я пытаюсь настроить два проекта Gradle таким образом, чтобы один проект использовал файлы, созданные другим. Первый проект добавляется ко второму с помощью includeBuild, и файл определяется во втором проекте как зависимость.

Проект testA

settings.gradle:

rootProject.name = 'testA'

build.gradle:

group = 'org.test'
version = '0.0.0.1_test'

task someZip (type: Zip) {
    from './settings.gradle'
    archiveName = 'xxx.zip'
    destinationDir = file("${buildDir}/test")
}

artifacts {
    //TODO add something here?
}

Проект testB

settings.gradle:

rootProject.name = 'testB'

if (System.getenv('LOCAL_COMPILATION') == 'true') {
    includeBuild '../testA'
}

build.gradle:

if (System.getenv('LOCAL_COMPILATION') != 'true') {
    repositories {
        maven { url '192.168.1.100' }
    }
}

configurations {
    magic
}

dependencies {
    magic 'org.test:xxx:0.0.0.+@zip'
}

task ultimateZip (type: Zip) {
    from configurations.magic
    archiveName = 'ultimate.zip'
    destinationDir = file("${buildDir}/ultimate-test")
}

Описание

Вы могли заметить, что в примере есть возможность использовать репозиторий maven. Я хотел подчеркнуть, что в конечном итоге появится возможность сделать это. Использование репозитория Maven не является целью этого вопроса, за исключением того, что решение не должно мешать этому. (Другими словами, вы можете предположить, что System.getenv('LOCAL_COMPILATION') == 'true'.)

Вопрос в том, как определить артефакт таким образом, чтобы другой проект смог его распознать.

Предпочтительное решение должно быть похоже на то, что делает плагин Java, потому что я использую зависимости jar в своих проектах, и они работают как через includeBuild, так и через репозиторий.


person NO_NAME    schedule 19.07.2019    source источник


Ответы (1)


Следующая настройка должна работать (проверено с Gradle 5.5.1). В основном это соответствует вашей первоначальной настройке, за исключением изменений, обозначенных XXX.

Проект testA

settings.gradle:

rootProject.name = 'testA'

build.gradle:

group = 'org.test'
version = '0.0.0.1_test'

task someZip (type: Zip) {
    from './settings.gradle'
    archiveName = 'xxx.zip'
    destinationDir = file("${buildDir}/test")
}

// XXX (replaced your empty "artifacts" block)
configurations.create('default')
def myArtifact = artifacts.add('default', someZip) {
    name = 'xxx'
}

// XXX (only added to show that publishing works)
apply plugin: 'maven-publish'
publishing {
    repositories {
        maven { url = 'file:///tmp/my-repo' }
    }
    publications {
        myPub(MavenPublication) {
            artifactId myArtifact.name
            artifact myArtifact
        }
    }
}

Проект testB

settings.gradle:

rootProject.name = 'testB'

if (System.getenv('LOCAL_COMPILATION') == 'true') {
    // XXX (added a dependency substitution to let Gradle know that
    //      "org.test:xxx" corresponds to the testA project)
    includeBuild('../testA') {
        dependencySubstitution {
            substitute module('org.test:xxx') with project(':')
        }
    }
}

build.gradle:

if (System.getenv('LOCAL_COMPILATION') != 'true') {
    repositories {
        // XXX (only changed to show that resolution still works after
        //      publishing)
        maven { url = 'file:///tmp/my-repo' }
    }
}

configurations {
    magic
}

dependencies {
    magic 'org.test:xxx:0.0.0.+@zip'
}

task ultimateZip (type: Zip) {
    from configurations.magic
    archiveName = 'ultimate.zip'
    destinationDir = file("${buildDir}/ultimate-test")
}

Как просили в комментариях, вот еще несколько пояснений по созданной конфигурации default и добавленному артефакту в проекте testA.

Составные сборки в Gradle в настоящее время имеют ограничение, заключающееся в том, что замененные зависимости проекта "всегда будут указывать к default конфигурации целевого проекта”. В вашем примере это означает, что testA необходимо опубликовать в конфигурации default. Таким образом, мы сначала создаем конфигурацию default. Обратите внимание, что некоторые плагины (например, java) уже создают эту конфигурацию; вам не нужно создавать его самостоятельно при использовании таких плагинов.

Кажется, это нигде не упоминается явно, но, как вы, кажется, уже сами выяснили, PublishedArtifacts проекта (как объявлено с project.artifacts) важны для Gradle, чтобы выяснить связывание зависимостей в составных сборках. Следовательно, мы обязательно объявляем такой PublishedArtifact в testA, используя этот API. Артефакт (например, его расширение) настраивается на основе свойств задачи someZip. Кажется, имя не взято из задачи someZip в вашем примере, потому что вы вручную установили archiveName; следовательно, нам нужно явно объявить это. Если вместо этого вы используете archiveBaseName = 'xxx' в someZip, вам не нужно замыкание при добавлении артефакта.

person Chriki    schedule 27.07.2019
comment
Эта штука с расширением может быть проблемой, когда один проект генерирует два файла с одинаковым именем и разными расширениями. Думаю, у меня есть один или два таких проекта. - person NO_NAME; 28.07.2019
comment
Мне не нравится наличие dependencySubstitution в файле настроек проекта testB. Есть две причины: 1) Я включаю один и тот же проект в несколько других проектов, поэтому будет много повторяющегося кода. 2) Мой реальный код для includeBuild - это не просто if, а функция, которая проверяет несколько разных папок, ищет нужный проект. Если я добавлю к нему еще больше кода, он будет довольно беспорядочным. Можно ли перевести dependencySubstitution в проект testA? build.gradle проекта testB также было бы приемлемо, потому что я мог бы написать плагин для этого. - person NO_NAME; 28.07.2019
comment
Я нашел способ сохранить явно объявленное расширение зависимости в testB; пожалуйста, смотрите мой обновленный ответ. Что касается подстановки зависимостей, то, к сожалению, она необходима, если ваш подключаемый проект имеет другое имя (testA), чем имя модуля, который он публикует (xxx). Я не верю, что в настоящее время существует какой-либо способ переместить подстановку зависимостей из settings.gradle. Тем не менее, можно ли будет переименовать testA в xxx? Тогда вам вообще не понадобилась бы замена, и установка тоже выглядела бы чище (из того, что я знаю о вашей настройке из вопроса). - person Chriki; 28.07.2019
comment
Я думаю, что в случае большинства проектов название артефакта такое же, как у проектов. Я показал самый крайний случай. Итак, мне не нужно использовать dependencySubstitution, когда имена совпадают? - person NO_NAME; 28.07.2019
comment
Цель большей части кода довольно ясна, но не могли бы вы добавить пояснения к этим 4 строкам после // XXX (replaced your empty "artifacts" block)? Я хочу знать, как именно это работает, чтобы я мог изменить это, если это необходимо. Особенно хотелось бы узнать, для чего предназначена конфигурация default. Я предполагаю, что присвоение значения myArtifact не обязательно, если вы не планируете использовать его позже для публикации? - person NO_NAME; 28.07.2019
comment
Да, когда вы используете rootProject.name = 'xxx' в testA/settings.gradle, вам не нужен dependencySubstitution. Вам действительно нужно определить переменную myArtifact только тогда, когда вы планируете использовать ее позже. Я добавил еще несколько объяснений в конце своего ответа по другим пунктам, которые вы упомянули. - person Chriki; 29.07.2019
comment
Теперь я знаю, почему я мог понять это сам. Возникла проблема при применении плагина java к проекту testA. Вероятно, это другая проблема, чем я представил здесь, поэтому я решил создать новый вопрос: stackoverflow.com/questions/57272576/ - person NO_NAME; 30.07.2019