Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-59108

Artifactory plugin can't publish build info for Gradle builds

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Critical Critical
    • None
    • Linux
      Jenkins v2.189
      Artifactory Plugin v3.3.2
      Gradle Plugin v1.33
      Pipeline Plugin v2.6

      We have been using the Gradle and Artifactory plugins on our production Jenkins instance for years using the traditional freestyle job types. We are now working on migrating all of our production builds to use Jenkins Pipeline scripts. As part of that transition we have a need to build Java projects using Gradle and publish artifacts generated by these projects to Artifactory. Further, nearly all of our production builds are performed within dockerized build environments so all build time dependencies can be managed and reproduced. However, I can not for the life of me find a way to get a simple Gradle operation to publish artifacts along with the requisite build info and back-links to the Artifactory build information. Here is an brief example of the sort of build configuration we are looking to use (in scripted pipeline format):

       

      node {
        stage ("build") {
          // checkout project sources
          checkout scm
      
          // get artifactory connection parameters
          def artifactory_server = Artifactory.server 'server-id'
      
          // construct a gradle build object
          def gradle_proxy = Artifactory.newGradleBuild()
      
          // configure the gradle build environment to use the gradle wrapper
          gradle_proxy.deployer repo: "snapshot-repo", server: artifactory_server
          gradle_proxy.useWrapper = true  // <---- this option appears to be undocumented but I found it when I went looking through the source for the plugin
      
          // build docker build environment from the source repo
          container = docker.build("./docker")
      
          // launch the build environment
          container.inside() {
            // try to build the gradle project...
            // this operation fails
            build_info = gradle_proxy.run rootDir: "master", buildFile: "build.gradle", tasks: ":subproj:artifactoryPublish"
      
            // publish build info if/when the build succeeds
            artifactory_server.publishBuildInfo buildInfo
          }
        }
      } 

       

       

      When running this build, the call to the gradle_proxy.run task produces the following error:

      expected to call org.jfrog.hudson.pipeline.common.types.packageManagerBuilds.GradleBuild.run but wound up catching ArtifactoryGradleBuild; see: https://jenkins.io/redirect/pipeline-cps-method-mismatches/ 

      I will say that I am sort of flying blind here. Most of the docs and examples I've found online that integrate Gradle, Jenkins and Artifactory assume that you are using a freestyle job configuration or that you are using a Gradle binary (ie: not the Gradle wrapper) which is deployed explicitly by Jenkins, which is not something we can/want to do in our case. Also, I am not sure if Docker is somehow playing a part in this problem because none of the examples I've found online to orchestrate this type of build use Docker. So maybe this behavior / result is unique to this specific combination of build tools.

      If anyone can tell me whether or not I've missed something obvious here in my build script, or perhaps point me to some documentation or examples that shows how to orchestrate this type of build, I would really appreciate it.

          [JENKINS-59108] Artifactory plugin can't publish build info for Gradle builds

          I probably should mention that I have successfully managed to get parts of the jenkins-gradle-artifactory integration to work in isolation from one another. For example, if I create a spec file that lists all the artifacts produced by the Gradle build and pass that to the Artifactory server instance in the Jenkins build script, I can publish the artifacts and build information is correctly attached to the files, and hyperlinks to the buildinfo records are added to the Jenkins build pages. However this solution forces me to duplicate the list of artifacts - once in the build.gradle file and again in the file spec in the Jenkinsfile. So sooner or later one of these is bound to get out of sync and break.

          Similarly, if I don't use any of the Jenkins Artifactory plugin logic directly, but merely call `./master/gradlew artifactoryPublish`, Gradle will successfully publish files to Artifactory. However, the Jenkins build info is not attached to the published artifacts and the hyperlinks in the Jenkins build pages are not added, so this is not a workable solution either.

          Kevin Phillips added a comment - I probably should mention that I have successfully managed to get parts of the jenkins-gradle-artifactory integration to work in isolation from one another. For example, if I create a spec file that lists all the artifacts produced by the Gradle build and pass that to the Artifactory server instance in the Jenkins build script, I can publish the artifacts and build information is correctly attached to the files, and hyperlinks to the buildinfo records are added to the Jenkins build pages. However this solution forces me to duplicate the list of artifacts - once in the build.gradle file and again in the file spec in the Jenkinsfile. So sooner or later one of these is bound to get out of sync and break. Similarly, if I don't use any of the Jenkins Artifactory plugin logic directly, but merely call `./master/gradlew artifactoryPublish`, Gradle will successfully publish files to Artifactory. However, the Jenkins build info is not attached to the published artifacts and the hyperlinks in the Jenkins build pages are not added, so this is not a workable solution either.

          I just create a new test build with a smaller Gradle project that didn't have any dependencies that required a Dockerized build environment (ie: so I could do the same build sequence without the Docker dependency) and I still received the error/warning message mentioned above. However, I hit another Gradle error that is different and not obviously related to the previous warning:
          An exception occurred applying plugin request [id: 'com.jfrog.artifactory', version: '4.9.8']
          > Failed to apply plugin [id 'com.jfrog.artifactory']
          > Cannot cast object 'org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention@4c55d658' with class 'org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention' to class 'org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention'
          I'm not yet sure what is breaking here but my original problem statement still holds: I am unable to publish build info for a Gradle build that uses the Artifactory plugin.

          Kevin Phillips added a comment - I just create a new test build with a smaller Gradle project that didn't have any dependencies that required a Dockerized build environment (ie: so I could do the same build sequence without the Docker dependency) and I still received the error/warning message mentioned above. However, I hit another Gradle error that is different and not obviously related to the previous warning: An exception occurred applying plugin request [id: 'com.jfrog.artifactory', version: '4.9.8'] > Failed to apply plugin [id 'com.jfrog.artifactory'] > Cannot cast object 'org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention@4c55d658' with class 'org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention' to class 'org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention' I'm not yet sure what is breaking here but my original problem statement still holds: I am unable to publish build info for a Gradle build that uses the Artifactory plugin.

          So, just to be clear, my simplified build configuration that produced the previous error message looks like this:

          node  {
              stage ("build") {
                  checkout scm
                 
                  def artifactory_server = Artifactory.server 'server-id' 
                  
                  def gradle_proxy = Artifactory.newGradleBuild()          
                  gradle_proxy.deployer repo: 'snapshot-repo', server: artifactory_server
                  gradle_proxy.useWrapper = true
                  
                  def build_info = gradle_proxy.run tasks: "artifactoryPublish"
                  
                  artifactory_server.publishBuildInfo build_info
              } // stage
          } // node 

          Kevin Phillips added a comment - So, just to be clear, my simplified build configuration that produced the previous error message looks like this: node { stage ( "build" ) { checkout scm def artifactory_server = Artifactory.server 'server-id' def gradle_proxy = Artifactory.newGradleBuild() gradle_proxy.deployer repo: 'snapshot-repo' , server: artifactory_server gradle_proxy.useWrapper = true def build_info = gradle_proxy.run tasks: "artifactoryPublish" artifactory_server.publishBuildInfo build_info } // stage } // node

          Also worth noting, using the exact same build configuration I can replace the call to gradle_proxy.run with a shell build step that calls into gradlew and the build succeeds ... however there is no build info attched to the artifacts that are published by Gradle to Artifactory. Here's a sample of the build script that I am describing:

           

          node  {
              stage ("build") {
                  checkout scm
                 
                  def artifactory_server = Artifactory.server 'server-id' 
                  
                  def gradle_proxy = Artifactory.newGradleBuild()          
                  gradle_proxy.deployer repo: 'snapshot-repo', server: artifactory_server
                  gradle_proxy.useWrapper = true
                  
                  def build_info = Artifactory.newBuildInfo()
                  sh "./gradlew artifactoryPublish"
                  artifactory_server.publishBuildInfo build_info
              } // stage
          } // node  

          Kevin Phillips added a comment - Also worth noting, using the exact same build configuration I can replace the call to gradle_proxy.run with a shell build step that calls into gradlew and the build succeeds ... however there is no build info attched to the artifacts that are published by Gradle to Artifactory. Here's a sample of the build script that I am describing:   node { stage ( "build" ) { checkout scm def artifactory_server = Artifactory.server 'server-id' def gradle_proxy = Artifactory.newGradleBuild() gradle_proxy.deployer repo: 'snapshot-repo' , server: artifactory_server gradle_proxy.useWrapper = true def build_info = Artifactory.newBuildInfo() sh "./gradlew artifactoryPublish" artifactory_server.publishBuildInfo build_info } // stage } // node

          After examining the build output a little closer, I noticed that when using the GradleBuild object to proxy the call to Gradle, the gradle wrapper is given an "init script" that appears to be generated by the Artifactory Jenkins plugin. I dug into one our build servers so I could crack open one of these init scripts to see what it looks like and here's what I found:

          import org.jfrog.gradle.plugin.artifactory.ArtifactoryPlugin
          import org.jfrog.gradle.plugin.artifactory.task.ArtifactoryTaskinitscript {
              dependencies {
                  classpath fileTree('<path_to_jenkins_temp_folder>/artifactory/cache/artifactory-plugin/3.3.2')
              }
          }addListener(new BuildInfoPluginListener())
          class BuildInfoPluginListener extends BuildAdapter {    def void projectsLoaded(Gradle gradle) {
                  Map<String, String> projectProperties = new HashMap<String, String>(gradle.startParameter.getProjectProperties())
                  projectProperties.put("build.start", Long.toString(System.currentTimeMillis()))
                  gradle.startParameter.setProjectProperties(projectProperties)
                  Project root = gradle.getRootProject()
                  root.logger.debug("Artifactory plugin: projectsEvaluated: ${root.name}")
                  if (!"buildSrc".equals(root.name)) {
                      root.allprojects {
                          apply {
                              apply plugin: ArtifactoryPlugin
                          }
                      }
                  }        // Set the "archives" configuration to all Artifactory tasks.
                  for (Project p : root.getAllprojects()) {
                      Task t = p.getTasks().findByName(ArtifactoryTask.ARTIFACTORY_PUBLISH_TASK_NAME)
                      if (t != null) {
                          ArtifactoryTask task = (ArtifactoryTask)t
                          task.setAddArchivesConfigToTask(true)
                      }
                  }
              }
          } 

          The most notable part I think in the init script is the absolute class path to a temporary folder where there is apparently a  gradle / java dependency named "artifactory-plugin" which appears to be pegged at version 3.3.2 (ie: the same version as the Jenkins Artifactory plugin). So I can't help but think there must be a class defined in the Jenkins Artifactory plugin that is also defined in the Gradle Artifactory plugin and the two class definitions are incompatible with one another, and that is the cause of the Java casting error I mentioned in my earlier comment.

          Honestly, I have no idea how any of this works ... or is supposed to work. If there is an interdependency between the Artifactory plugin for Gradle and the Artifactory plugin for Jenkins that would preclude mixing incompatible versions between the CI build environment and the application build environment.

          I sincerely hope someone out there can offer some advice on how to proceed here.

          Kevin Phillips added a comment - After examining the build output a little closer, I noticed that when using the GradleBuild object to proxy the call to Gradle, the gradle wrapper is given an "init script" that appears to be generated by the Artifactory Jenkins plugin. I dug into one our build servers so I could crack open one of these init scripts to see what it looks like and here's what I found: import org.jfrog.gradle.plugin.artifactory.ArtifactoryPlugin import org.jfrog.gradle.plugin.artifactory.task.ArtifactoryTaskinitscript { dependencies { classpath fileTree( '<path_to_jenkins_temp_folder>/artifactory/cache/artifactory-plugin/3.3.2' ) } }addListener( new BuildInfoPluginListener()) class BuildInfoPluginListener extends BuildAdapter { def void projectsLoaded(Gradle gradle) { Map< String , String > projectProperties = new HashMap< String , String >(gradle.startParameter.getProjectProperties()) projectProperties.put( "build.start" , Long .toString( System .currentTimeMillis())) gradle.startParameter.setProjectProperties(projectProperties) Project root = gradle.getRootProject() root.logger.debug( "Artifactory plugin: projectsEvaluated: ${root.name}" ) if (! "buildSrc" .equals(root.name)) { root.allprojects { apply { apply plugin: ArtifactoryPlugin } } } // Set the "archives" configuration to all Artifactory tasks. for (Project p : root.getAllprojects()) { Task t = p.getTasks().findByName(ArtifactoryTask.ARTIFACTORY_PUBLISH_TASK_NAME) if (t != null ) { ArtifactoryTask task = (ArtifactoryTask)t task.setAddArchivesConfigToTask( true ) } } } } The most notable part I think in the init script is the absolute class path to a temporary folder where there is apparently a  gradle / java dependency named "artifactory-plugin" which appears to be pegged at version 3.3.2 (ie: the same version as the Jenkins Artifactory plugin). So I can't help but think there must be a class defined in the Jenkins Artifactory plugin that is also defined in the Gradle Artifactory plugin and the two class definitions are incompatible with one another, and that is the cause of the Java casting error I mentioned in my earlier comment. Honestly, I have no idea how any of this works ... or is supposed to work. If there is an interdependency between the Artifactory plugin for Gradle and the Artifactory plugin for Jenkins that would preclude mixing incompatible versions between the CI build environment and the application build environment. I sincerely hope someone out there can offer some advice on how to proceed here.

          Yahav Itzhak added a comment -

          leedega, this warning introduced in the Groovy Plugin v 2.7.1 at this commit. More information can be found in JENKINS-58643.

          There is an open pull request that resolves it. You're welcome to vote up.

          At the meanwhile, you can ignore the meaningless warning.

          However, I didn't managed to understand. Does the artifacts been published to Artifactory or not? Do you see 'uploading' messages at the build log? Do you see them at the build-info page at Artifactory?

          Thanks.

          Yahav Itzhak added a comment - leedega , this warning introduced in the Groovy Plugin v 2.7.1 at this commit . More information can be found in JENKINS-58643 . There is an open pull request that resolves it. You're welcome to vote up. At the meanwhile, you can ignore the meaningless warning. However, I didn't managed to understand. Does the artifacts been published to Artifactory or not? Do you see 'uploading' messages at the build log? Do you see them at the build-info page at Artifactory? Thanks.

            yahaviz Yahav Itzhak
            leedega Kevin Phillips
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: