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

additional library() call not possible after failure

      When trying to load a shared library from a non existing branch it is not possible to load from default or master branch afterwards.

      Consider the following code:

      try {
        // try loading from branch
        library("sharedlib@${env.BRANCH_NAME}")
      }
      catch(Throwable e) {
        library("sharedlib")
      }

      Running this pipeline will result in something like

      [Pipeline] library
      Loading library sharedlib@feature/my-branch
      Attempting to resolve feature/my-branch from remote references...
      ...
      ERROR: Could not resolve feature/my-branch
      ...
      [Pipeline] library
      Only using first definition of library sharedlib

      It seems that "sharedlib" is recorded as "already loaded" despite the error.

       

          [JENKINS-64950] additional library() call not possible after failure

          Christoph Vogtländer added a comment - - edited

          As a workaround it is possible to remove the LibraryRecord from the LibrariesAction in the catch block:

          try {
            library("sharedlib@${env.BRANCH_NAME}")
          }
          catch(Throwable e) {
            def libs = currentBuild.rawBuild.getAction(LibrariesAction.class).getLibraries()
            libs.remove(libs.find { it.name == 'sharedlib' })
            currentBuild.rawBuild.replaceAction(new LibrariesAction(libs));
            libs = null
            library("sharedlib")
          }
          

          Christoph Vogtländer added a comment - - edited As a workaround it is possible to remove the LibraryRecord from the LibrariesAction in the catch block: try { library( "sharedlib@${env.BRANCH_NAME}" ) } catch (Throwable e) { def libs = currentBuild.rawBuild.getAction(LibrariesAction.class).getLibraries() libs.remove(libs.find { it.name == 'sharedlib' }) currentBuild.rawBuild.replaceAction( new LibrariesAction(libs)); libs = null library( "sharedlib" ) }

          Christoph Vogtländer added a comment - - edited

          Since the latest update to workflow-cps-global-lib 2.18 the workaround is no longer working (see JENKINS-41037): 

           

          java.lang.UnsupportedOperationException
           	at java.base/java.util.Collections$UnmodifiableCollection.remove(Collections.java:1063)
          

           

           

          Christoph Vogtländer added a comment - - edited Since the latest update to workflow-cps-global-lib 2.18 the workaround is no longer working (see JENKINS-41037 ):    java.lang.UnsupportedOperationException at java.base/java.util.Collections$UnmodifiableCollection.remove(Collections.java:1063)    

          New workaround which is compatible to getLibraries() returning an unmodifiable collection:

          try {
            library("sharedlib@${env.BRANCH_NAME}")
          }
          catch(Throwable e) {
            def libs = currentBuild.rawBuild.getAction(LibrariesAction.class).getLibraries()
            currentBuild.rawBuild.replaceAction(new LibrariesAction(libs.findAll { it.name != name }));
            libs = null
            library("sharedlib")
          }
          

          Christoph Vogtländer added a comment - New workaround which is compatible to getLibraries() returning an unmodifiable collection: try { library( "sharedlib@${env.BRANCH_NAME}" ) } catch (Throwable e) { def libs = currentBuild.rawBuild.getAction(LibrariesAction.class).getLibraries() currentBuild.rawBuild.replaceAction( new LibrariesAction(libs.findAll { it.name != name })); libs = null library( "sharedlib" ) }

          Daniel Geißler added a comment - - edited

          We do have another use case for this.

          The infrastructure we have is very unstable at times. That means randomly any git interaction is failing. We where able to fix that for the project checkout but then got caught by the checkout of the shared libraries.
          When trying to wrap that in a retry block we encountered the issue that is described here.

          The message seems to come from here:
          https://github.com/jenkinsci/pipeline-groovy-lib-plugin/blob/51f102305bb7df3f668a742003b86e9815d77426/src/main/java/org/jenkinsci/plugins/workflow/libs/LibraryAdder.java#L126

                              listener.getLogger().println("Only using first definition of library " + name);
          

          I am also sure it's because of these lines of code, where the librariesAction is already added with all the libraries to be loaded even before that has successfully been done:
          https://github.com/jenkinsci/pipeline-groovy-lib-plugin/blob/51f102305bb7df3f668a742003b86e9815d77426/src/main/java/org/jenkinsci/plugins/workflow/libs/LibraryAdder.java#L145-L153

                  // Record libraries we plan to load. We need LibrariesAction there first so variables can be interpolated.
                  build.addAction(new LibrariesAction(new ArrayList<>(librariesAdded.values())));
                  // Now actually try to retrieve the libraries.
                  for (LibraryRecord record : librariesAdded.values()) {
                      listener.getLogger().println("Loading library " + record.name + "@" + record.version);
                      for (URL u : retrieve(record, retrievers.get(record.name), listener, build, execution)) {
                          additions.add(new Addition(u, record.trusted));
                      }
                  }
          

          adding the library name only after it has successfully been retrieved should resolve the issue.

          Daniel Geißler added a comment - - edited We do have another use case for this. The infrastructure we have is very unstable at times. That means randomly any git interaction is failing. We where able to fix that for the project checkout but then got caught by the checkout of the shared libraries. When trying to wrap that in a retry block we encountered the issue that is described here. The message seems to come from here: https://github.com/jenkinsci/pipeline-groovy-lib-plugin/blob/51f102305bb7df3f668a742003b86e9815d77426/src/main/java/org/jenkinsci/plugins/workflow/libs/LibraryAdder.java#L126 listener.getLogger().println( "Only using first definition of library " + name); I am also sure it's because of these lines of code, where the librariesAction is already added with all the libraries to be loaded even before that has successfully been done: https://github.com/jenkinsci/pipeline-groovy-lib-plugin/blob/51f102305bb7df3f668a742003b86e9815d77426/src/main/java/org/jenkinsci/plugins/workflow/libs/LibraryAdder.java#L145-L153 // Record libraries we plan to load. We need LibrariesAction there first so variables can be interpolated. build.addAction( new LibrariesAction( new ArrayList<>(librariesAdded.values()))); // Now actually try to retrieve the libraries. for (LibraryRecord record : librariesAdded.values()) { listener.getLogger().println( "Loading library " + record.name + "@" + record.version); for (URL u : retrieve(record, retrievers.get(record.name), listener, build, execution)) { additions.add( new Addition(u, record.trusted)); } } adding the library name only after it has successfully been retrieved should resolve the issue.

            Unassigned Unassigned
            gordin Christoph Vogtländer
            Votes:
            1 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: