Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 435
kkooff114 Avatar asked Jul 09 '18 14:07

kkooff114


2 Answers

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.

like image 82
bvarga Avatar answered Sep 23 '22 06:09

bvarga


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.

like image 31
Mark McKenna Avatar answered Sep 25 '22 06:09

Mark McKenna