Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Artifact name and version configured in publication are not used when publishing project dependencies #11299

Closed
vlsi opened this issue Nov 10, 2019 · 16 comments
Assignees
Milestone

Comments

@vlsi
Copy link
Contributor

vlsi commented Nov 10, 2019

Expected Behavior

Gradle should take artifactId and version from MavenPublication when generating pom.xml

Current Behavior

Gradle uses version from project, and it uses project.name for artifactId.

Context

This impacts BOM generation for ApacheJMeter.
Historically, Maven artifacts were named like ApacheJMeter_core while the folder layout was just core.

That is why JMeter uses artifactId != project.name in pom.xml for backward compatibility.

Steps to Reproduce

custom-artifact.zip
The test case is to execute (in any order) the following tasks: :bom:generatePomFileForBomPublication, :core:generatePomFileForCorePublication, :lib:generatePomFileForLibPublication

Just in case:

core:

plugins {
    `java-library`
    `maven-publish`
}


publishing {
    publications {
        create<MavenPublication>(project.name) {
            artifactId = "customized-core-artifact-name"
            version = "1.0.0"
            from(components["java"])
        }
    }
}

core/.../pom-default.xml (it is expected):

...
  <groupId>custom-artifacts</groupId>
  <artifactId>customized-core-artifact-name</artifactId>
  <version>1.0.0</version>
</project>

bom:

plugins {
    `java-platform`
    `maven-publish`
}

dependencies {
    // Parenthesis are needed here: https://github.com/gradle/gradle/issues/9248
    (constraints) {
        runtime(project(":core"))
    }
}

publishing {
    publications {
        create<MavenPublication>(project.name) {
            artifactId = "custom-bom"
            version = "1.1.0"
            from(components["javaPlatform"])
        }
    }
}

bom/.../pom-default.xml:

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>custom-artifacts</groupId>
        <artifactId>core</artifactId> <!-- WRONG ARTIFACT NAME. It should be customized-lib-artifact-name -->
        <version>unspecified</version> <!-- WRONG VERSINO. It sould be 1.0.0 -->
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

lib:

plugins {
    `java-library`
    `maven-publish`
}

dependencies {
    api(project(":core"))
}


publishing {
    publications {
        create<MavenPublication>(project.name) {
            artifactId = "customized-lib-artifact-name"
            version = "1.2.0"
            from(components["java"])
        }
    }
}

lib/.../pom-default.xml (it is OK):

  <artifactId>customized-lib-artifact-name</artifactId>
  <version>1.2.0</version>
  <dependencies>
    <dependency>
      <groupId>custom-artifacts</groupId>
      <artifactId>customized-core-artifact-name</artifactId>
      <version>1.0.0</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>

Your Environment

Gradle 6.0

@vlsi
Copy link
Contributor Author

vlsi commented Nov 10, 2019

If I add multiple MavenPublication instances to core project, then pom generation for lib fails as follows.
Note: I do not need to have multiple publications per project, so this error is completely fine for me

* What went wrong:
Execution failed for task ':lib:generatePomFileForLibPublication'.
> Publishing is not able to resolve a dependency on a project with multiple publications that have different coordinates.
  Found the following publications in project ':core':
    - Maven publication 'core' with coordinates custom-artifacts:customized-core-artifact-name:1.0.0
    - Maven publication 'core2' with coordinates custom-artifacts:customized-core-artifact-name2:1.0.0

However bom generation still somehow works even in case core has multiple publications which is strange. I expect bom fail in the same way as lib.

@vlsi
Copy link
Contributor Author

vlsi commented Nov 10, 2019

In case you wondered, Gradle 6.0 metadata is wrong as well:

./gradlew :bom:generateMetadataFileForBomPublication

module.json:

{
  "formatVersion": "1.1",
  "component": {
    "group": "custom-artifacts",
    "module": "custom-bom",
    "version": "1.1.0",
    "attributes": {
      "org.gradle.status": "release"
    }
  },
  "createdBy": {
    "gradle": {
      "version": "6.0",
      "buildId": "4in6ac5zknfj5nxjsucbagvii4"
    }
  },
  "variants": [
    {
      "name": "apiElements",
      "attributes": {
        "org.gradle.category": "platform",
        "org.gradle.usage": "java-api"
      }
    },
    {
      "name": "runtimeElements",
      "attributes": {
        "org.gradle.category": "platform",
        "org.gradle.usage": "java-runtime"
      },
      "dependencyConstraints": [
        {
          "group": "custom-artifacts",
          "module": "core",
          "version": {
            "requires": "unspecified"
          }
        }
      ]
    }
  ]
}

@bdellegrazie
Copy link

Since I'd already prepared this https://github.com/bdellegrazie/gradle-java-platform-sample before discovering this bug report, I'll link to it.
It demonstrates exactly the same behaviour as described above, using Gradle's own multi-project sample for the java-platform plugin. In our case, we prefix the artifactId's with 'example-' before publication but the BOM uses the project name rather than the maven publication artifactId

@sergei-ivanov
Copy link

Ideally, it would be great if the fix was also backported to Gradle 5.x (it should be easy, as there has been no changes in the affected code between 5.x and 6.0). Unfortunately we cannot migrate to 6.0 right now because of incompatible changes that make our build fail.

@jjohannes jjohannes changed the title java-platform uses version and artifact from project info rather from MavenPublication Artifact name and version configured in publication are not used when publishing project dependencies Dec 12, 2019
@jjohannes
Copy link
Contributor

So it took me a bit to sort through this. :)

At first, I think the title of the issue was misleading so I updated it. The following is working (we were thinking that is what this is all about):

plugins {
    `java-platform`
    `maven-publish`
}

publishing {
    publications {
        create<MavenPublication>(project.name) {
            artifactId = "custom-bom" // The publication of the platform will have this name
            version = "1.1.0"  // The publication of the platform will have this version
            from(components["javaPlatform"])
        }
    }
}

If you add a constraint on a project to the platform, it is also working and it is published correctly:

dependencies {
    constraints {
        runtime(project(":core"))
    }
}

(If in :core, you define the artifact name by the project name and the version by setting the version on the project.)

What is NOT working Is if you change the name/version in the publication, it is not reflected when the project dependencies is resolved to coordinates. I am not surprised by that. In fact, I am not convinced anything should be changed here. (Except for maybe giving some kind of warning/errror during publishing instead of publishing something that does not work.)

The whole idea of configuring essential parts of the component inside the publication is flawed. It is possible (because it always was), but I think if we are talking about publishing Java projects, the recommendation should be not to use that. Which includes APIs like artifactId, version, artifact(), etc. Because if these define the identity of the project/component, what happens if I define multiple publications? Also the identity is then different in the local and remote version (i.e. a project has different coordinates locally than its published counterpart). Ideally, a publication only looks like this:

create<MavenPublication>("a-name-that-does-not-matter") {
    from(components["..."])
}

Plus maybe some informal metadata like licensing etc. (for which we do not have a better API yet) and some POM manipulation if something "special" needs to be done for Maven consumers.

So all parts that make up the identity and interface (i.e. outgoing/published artifacts) should be defined globally for the project or in the "component" that is published (ideally there is only one component per project).

So I would like to understand what your use cases are to configure these things in the publication.

@bdellegrazie In your example, you could remove the artifactId = 'example-' + project.name config from build.gradle and instead adjust the project names in settings.gradle (without changing the folder name). For example by adding this to settings.gradle:

rootProject.children.each { subproject ->
    subproject.name = 'example-' + subproject.name
}

@vlsi @sergei-ivanov could your issue(s) also be solved like this? If not, can you explain what is missing?

Note: I am a bit surprised that #11317 works. Seems like we already take one (the first??) publication into account when resolving a project's coordinates. However, I am (currently) not convinced that we should go down that road further (as explained above).

@bdellegrazie
Copy link

@jjohannes I will try your suggestion - thank you.

@vlsi
Copy link
Contributor Author

vlsi commented Dec 12, 2019

@jjohannes , can you please share the project that is "working" for you?

I did provide a full-blown example (see custom-artifact.zip in the first message):

$ unzip custom-artifact.zip
$ ./gradlew generatePomFileForBomPublication
$ cat bom/build/publications/bom/pom-default.xml

...
      <dependency>
        <groupId>custom-artifacts</groupId>
        <artifactId>core</artifactId>
        <version>unspecified</version>
      </dependency>

@vlsi
Copy link
Contributor Author

vlsi commented Dec 12, 2019

you could remove the artifactId = 'example-' + project.name config from build.gradle and instead adjust the project names in settings.gradle (without changing the folder name). For example by adding this to settings.gradle:

It would make command-line harder to use.

For instance, Apache JMeter artifacts have names like ApacheJMeter_core.
It would be extremely sad to use Gradle commands like ./gradlew :src:ApacheJMeter_core:jar
Currently, we have :src:core:jar which is typable.

@jjohannes
Copy link
Contributor

@vlsi Regarding #11299 (comment): That is not working, because the artifact name/version is configured in the publishing { .. } only. Sorry if that was not clear.

If the only problem with the solution is the command line, then you can also do something like this in settings.gradle.

gradle.startParameter.taskNames = gradle.startParameter.taskNames.collect { taskName ->
    taskName.contains(':') ? 'example-' + taskName : taskName
}

It's a bit of a hack, but I think it is still better to do it this way around (i.e. not change the identity of the projects). If you want/need to keep the "old" name, the projects should also use that for their identity I would say. Because it is not just a publishing detail. It is the public identity and everyone consuming your published component also needs to continue to use the "old" name.

@vlsi
Copy link
Contributor Author

vlsi commented Dec 12, 2019

That is not working, because the artifact name/version is configured in the publishing { .. } only

I do not follow that :(
Do you mean "project name must always be the same as Maven artifactId"?

Do you mean you are going to deprecate and remove https://docs.gradle.org/current/userguide/publishing_maven.html#sec:identity_values_in_the_generated_pom ?

If you review DefaultMavenPublication.java and GradleModuleMetadataWriter.java you'll see that both those classes perform extra resolving like the following: https://github.com/gradle/gradle/blob/7c95b1b75edf091b6e63d9c4ab83d655a20f054f/subprojects/maven/src/main/java/org/gradle/api/publish/maven/internal/publication/DefaultMavenPublication.java#L435

However, the resolution via projectDependencyResolver is performed only for regular project dependencies.
Dependency constraints are not "resolved" though projectDependencyResolver, thus it causes the issue as described in the very first comment. It is exactly what #11317 implements: it adds "resolution" for ProjectDependencyConstraints which is implemented in a very similar way what was used for ProjectDependencies.

Having project name != folder name consumes space in IDEA as well (as it starts to show both folder name and actual project name in brackets)

you can also do something like this in settings.gradle.

Parsing the command-line does not seem to be fun.

It is the public identity and everyone consuming your published component also needs to continue to use the "old" name

"old" publication was implemented in Apache Ant. Now the project is migrated to Gradle, and artifactId in the publications is there to make the publication names to be exactly the same as they were with Ant.

@jjohannes
Copy link
Contributor

jjohannes commented Dec 13, 2019

We discussed this again internally and since this is working for dependencies, I was convinced that it should also work for constraints. Thanks for your patience and feedback. We will have another look at your PR @vlsi and see that we get it integrated.

@vlsi
Copy link
Contributor Author

vlsi commented Dec 13, 2019

@jjohannes , thank you.

I see that "what if a project has multiple publications with all having different ids" is a slippery slope (which is to use when project("...") is used?), but I was more like curious on your vision (+ there was some resolution for regular ProjectDependencies).

@jjohannes jjohannes self-assigned this Dec 16, 2019
@jjohannes jjohannes added this to the 6.1 RC1 milestone Dec 16, 2019
jjohannes pushed a commit to vlsi/gradle that referenced this issue Dec 16, 2019
fixes gradle#11299

Signed-off-by: Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
@jjohannes
Copy link
Contributor

Your PR is in for 6.1 @vlsi. Thanks again! With 6.1 all the samples provided here should work as they are. Please feel free to try it with the next nightly tomorrow.

@bdellegrazie
Copy link

@jjohannes any chance it could be backported to 5.4.x please?

@jjohannes
Copy link
Contributor

@bdellegrazie We have no concrete plan for another 5.4.x release at the moment. If that should change, we can consider to include this.

In the meantime, can you confirm that the fix is working for you (e.g. with the latest nightly 6.1-20191217025822+0000)?

Is there anything specific blocking you to move to 6.x?

@markATavail
Copy link

markATavail commented Jun 29, 2020

So it took me a bit to sort through this. :)
[...]
The whole idea of configuring essential parts of the component inside the publication is flawed. It is possible (because it always was), but I think if we are talking about publishing Java projects, the recommendation should be not to use that. Which includes APIs like artifactId, version, artifact(), etc. Because if these define the identity of the project/component, what happens if I define multiple publications? Also the identity is then different in the local and remote version (i.e. a project has different coordinates locally than its published counterpart). Ideally, a publication only looks like this:

Having just wasted two WEEKS trying to get two packages to publish, I finally discovered this obscure comment in a closed issue. Removing the explicit artifactId and version finally allowed me to publish two modules without Gradle failing internally. The artifactId and version are explicitly set in every example everywhere, and every example and shred of documentation implies that they're even mandatory. This issues is not actually complete until you FIX THE DESIGN FLAW and UPDATE THE DOCUMENTATION.

Also, please do the obvious thing and introduce publicationArtifactId and publicationVersion as project extension fields that the publication plugin looks for (falling back to the project's name and version if absent). And then remove forever those broken fields from publication.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants