Publishing is not able to resolve a dependency on a project with multiple publications that have different coordinates
Asked Answered
D

3

18

I have 2 lib modules : library , library2, and use android-maven-publish to publish my multi-modules android project with multi-productFlavors

build.gradle in library:

apply plugin: 'com.android.library'
apply plugin: 'digital.wup.android-maven-publish'

android {
    compileSdkVersion 26
    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    flavorDimensions "runner"
    productFlavors {
        sit {
            dimension "runner"
        }
        dev {
            dimension "runner"
        }
        uat {
            dimension "runner"
        }
        prd {
            dimension "runner"
        }
    }

}

dependencies {
   ...
  implementation project(':android-library2')
}

apply from: '../publish.gradle'

build.gradle in library2:

apply plugin: 'com.android.library'
apply plugin: 'digital.wup.android-maven-publish'

android {
    compileSdkVersion 26
    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    flavorDimensions "runner"
    productFlavors {
        sit {
            dimension "runner"
        }
        dev {
            dimension "runner"
        }
        uat {
            dimension "runner"
        }
        prd {
            dimension "runner"
        }
    }

}

dependencies {
   ...
}

apply from: '../publish.gradle'

publish.gradle:

publishing.publications() {
    android.libraryVariants.all { variant ->
        "maven$project.archivesBaseName${variant.name.capitalize()}Aar"(MavenPublication) {
            from components.findByName("android${variant.name.capitalize()}")
            groupId 'com.android.saleshelp'
            artifactId project.archivesBaseName + "-${variant.name.capitalize()}"
            version android.defaultConfig.versionName
        }
    }
}

publishing.repositories {
    mavenLocal()
}

when I run task publish in library, I got the following error:

* What went wrong:
Could not determine the dependencies of task ':android-library2:publishMavenandroid-library2SitReleaseAarPublicationToMavenLocalRepository'.
> Publishing is not able to resolve a dependency on a project with multiple publications that have different coordinates.
  Found the following publications in project ':android-library':
    - Maven publication 'mavenandroid-libraryPrdDebugAar' with coordinates com.cestbon.android.saleshelp:android-library-PrdDebug:1.0
    - Maven publication 'mavenandroid-libraryPrdReleaseAar' with coordinates com.cestbon.android.saleshelp:android-library-PrdRelease:1.0
    - Maven publication 'mavenandroid-libraryDevDebugAar' with coordinates com.cestbon.android.saleshelp:android-library-DevDebug:1.0
    - Maven publication 'mavenandroid-libraryDevReleaseAar' with coordinates com.cestbon.android.saleshelp:android-library-DevRelease:1.0
    - Maven publication 'mavenandroid-libraryUatDebugAar' with coordinates com.cestbon.android.saleshelp:android-library-UatDebug:1.0
    - Maven publication 'mavenandroid-libraryUatReleaseAar' with coordinates com.cestbon.android.saleshelp:android-library-UatRelease:1.0
    - Maven publication 'mavenandroid-librarySitDebugAar' with coordinates com.cestbon.android.saleshelp:android-library-SitDebug:1.0
    - Maven publication 'mavenandroid-librarySitReleaseAar' with coordinates com.cestbon.android.saleshelp:android-library-SitRelease:1.0

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

If I removed apply from: '../publish.gradle' in build.gradle of library2, task :library:publish can be run successfully. But because of I want to publish library2 independently, so library2 must apply from: '../publish.gradle'

How can I do for this error? Thanks.

Environment: gradle 4.4 ~ 4.9-rc1

Danner answered 9/7, 2018 at 14:23 Comment(0)
B
9

It is a known limitation of the maven-publish plugin.

When a project dependency has multiple publications, the maven-publish plugin can't choose them properly. In your case, when the maven-publish plugin try to resolve implementation project(':android-library2'), it can't decide what to write to the pom file, because the android-library2 project has multiple publications with different coordinates.

In Gradle 4.9-rc-1 was intruduced an alias property. If you mark all publication as alias and you have a main publication, then this can solve your problem. But in my opinion this does not solve your problem completely, because the maven publish plugin will write the main publication's coordinates into the pom file independent of product flavors.

If that does not help, then you can use the workaround in the original bug report.

Bellhop answered 16/7, 2018 at 20:23 Comment(6)
I tried to look for documentation, couldn't find any help on how to use the alias property. I tried to add alias 'test'in the MavenPublication block, without success. I do have the property in DefaultMavenPublication since i use gradle 4.10.1. Could use an hint!Doubles
alias is boolean property. You can set true or false values only. You should use to flag the main publication with alias false and the alternative publication with alias trueBellhop
please could you post the syntax example where/how to call the void setAlias(boolean alias) method?Spun
publishing { publications { yourPublication(MavenPublication) { ... alias false}}}Olszewski
This works for me, but is this still the approach in 2022?Kuebbing
Since Gradle introduced the Module Metadata, I think the variant aware resolution can be an approach as well. You can read about in the offical documentation: docs.gradle.org/current/userguide/…Bellhop
K
6

I ran into the same problem, which appears to still be a limitation of maven-publish. I found a workaround that works pretty well for me:

publishing {
  repositories {
    def repositoryName = 'X'
    maven { name = repositoryName /* ... */ }
    
    afterEvaluate {
      def targetComponent = System.getProperty("targetComponent")
      components.each { component ->
        if (component.name != targetComponent) return

        def appendage = component.name.replaceAll("[Rr]elease", "")
        if (!appendage.isEmpty()) appendage = "-$appendage"

        publications {
          "${component.name}"(MavenPublication) {
            from component
            artifactId = project.name + appendage
          }
        }

        publish.doFirst {
          if (targetComponent == null)
            throw new GradleException("Deployment requires specifying -DtargetComponent option")
        }
      }
    }
  }
}

Invoke with gradle project:publish -DtargetComponent=release, or whatever other component you're trying to release.

Explanation: Gradle sees intra-workspace dependencies at the project level, but it outputs to Maven repos at the component level. Maven doesn't have this same project vs. component concept. This also means you can't specify, in a Gradle dependencies block, which component of a Maven-style dependency you are looking for (since Maven doesn't really get that concept). The result: Gradle can't figure out how to write the POM file entry for an intra-workspace dependency with multiple publications.

Minimal problem example:

// a/build.gradle:
publications {
  release(MavenPublication) { from components.release }
  debug(MavenPublication) { from components.debug; artifactId = 'a-debug' }
}

// b/build.gradle:
dependencies {
  project(':a') // ERROR: should this be 'group:b:1.0.0' or 'group:b-debug:1.0.0'?
}

The workaround works by having you indicate which component you want to deploy, across all projects, before configuration time. During configuration, Gradle only generates one publication per project, based on the component you flagged, adding the extra information Gradle needs to map intraproject deps to Maven-style deps. You only need to specify the command line argument when you want to deploy; the conditional is bound to the publish task, so it only goes off if that task is actually invoked.

Limitations:

  • Assumes that component information should be preserved in the Maven artifactId; you could change this if you wanted to
  • If you don't specify the property, gradle publish --dry-run doesn't show meaningful results
  • Gradle can only publish one component in each invocation
  • Every project in your workspace has to expose similarly-named components (you could tailor this code to fix that, though), and they all bind within that selection (i.e. a:release binds to b:release and a:debug binds to b:debug)

EDIT: I had called my task deploy but renamed it to publish when writing this answer. Turns out maven-publish creates a task publish automatically which does exactly what I wanted. I've updated the code snippet to reflect this.

EDIT2: Throw GradleException instead; it's slightly more idiomatic.

Korella answered 2/10, 2020 at 18:46 Comment(0)
K
4

Since Android Gradle Plugin (AGP) v7.1.0, it's possible to publish library variants as one Maven publication. See the release notes.

The release notes currently link to the wrong page (it doesn't contain examples). The page that it should probably link to, and that has various examples, is this one. Look for one of the multipleVariants examples.

Kuebbing answered 26/1, 2022 at 12:27 Comment(2)
This works for me! The only downside is that it doesn't publish the debug variants as far as I can tell. That can be useful for non-public testing & debugging.Nicosia
I am incorrect. It looks like it publishes them in a single POM via a classifier, so debug is included.Nicosia

© 2022 - 2024 — McMap. All rights reserved.