moakley
moakley

Reputation: 75

UnsupportedOperationException: must specify $class with an implementation of interface java.util.List

Running a Jenkinsfile test and the following stage is returning UnsupportedOperationException: must specify $class with an implementation of interface java.util.List

stage('Checkout') {
    steps {
        checkout([$class: 'GitSCM', 
            branches: [name: '*/master'], 
            doGenerateSubmoduleConfigurations: false, 
            extensions: [[$class: 'CleanBeforeCheckout'], 
                [$class: 'RelativeTargetDirectory', relativeTargetDir: 'targetDir']], 
            submoduleCfg: [], 
            userRemoteConfigs: [[credentialsId: 'jenkinsserviceaccount',
                url: 'https://bitbucket.company.net/scm/moak/myTestRepo.git']]])
    }
}

I did change some names after the fact for posting here, but the above was created using the Jenkins snippet generator. Any idea on what may be going wrong with the checkout?

Here is more of the exception I am seeing in the Jenkins console.

java.lang.UnsupportedOperationException: must specify $class with an implementation of interface java.util.List
    at org.jenkinsci.plugins.structs.describable.DescribableModel.resolveClass(DescribableModel.java:503)
    at org.jenkinsci.plugins.structs.describable.DescribableModel.coerce(DescribableModel.java:402)
    at org.jenkinsci.plugins.structs.describable.DescribableModel.buildArguments(DescribableModel.java:341)
    at org.jenkinsci.plugins.structs.describable.DescribableModel.instantiate(DescribableModel.java:282)
Caused: java.lang.IllegalArgumentException: Could not instantiate 
    {extensions=[{$class=CleanBeforeCheckout}, {$class=RelativeTargetDirectory, relativeTargetDir=stateStore}], 
    submoduleCfg=[], 
    userRemoteConfigs=[{credentialsId=jenkinsserviceaccount, url=https://bitbucket.hylandqa.net/scm/moak/hyland-statestore.git}], 
    doGenerateSubmoduleConfigurations=false, 
    branches={name=*/master}} 
for GitSCM(userRemoteConfigs: UserRemoteConfig(url: String, name: String, refspec: String, credentialsId: String)[], 
    branches: BranchSpec(name: String)[], 
    doGenerateSubmoduleConfigurations: boolean, 
    submoduleCfg: org.kohsuke.stapler.NoStaplerConstructorException: There's no @DataBoundConstructor on any constructor of class hudson.plugins.git.SubmoduleConfig[], 
    browser: GitRepositoryBrowser{AssemblaWeb(repoUrl: String) | BitbucketWeb(repoUrl: String) | CGit(repoUrl: String) | FisheyeGitRepositoryBrowser(repoUrl: String) | 
        GitBlitRepositoryBrowser(repoUrl: String, projectName: String) | GitLab(repoUrl: String, version: String) | GitList(repoUrl: String) | GitWeb(repoUrl: String) | 
        GithubWeb(repoUrl: String) | Gitiles(repoUrl: String) | GitoriousWeb(repoUrl: String) | GogsGit(repoUrl: String) | KilnGit(repoUrl: String) | 
        Phabricator(repoUrl: String, repo: String) | RedmineWeb(repoUrl: String) | RhodeCode(repoUrl: String) | Stash(repoUrl: String) | 
        TFS2013GitRepositoryBrowser(repoUrl: String) | ViewGitWeb(repoUrl: String, projectName: String)}, 
        gitTool: String, extensions: GitSCMExtension{AuthorInChangelog() | 
        BuildChooserSetting(buildChooser: BuildChooser{AncestryBuildChooser(maximumAgeInDays: int, ancestorCommitSha1: String) | 
        DefaultBuildChooser() | InverseBuildChooser()}) | ChangelogToBranch(options: ChangelogToBranchOptions(compareRemote: String, compareTarget: String)) | 
        CheckoutOption(timeout: int) | CleanBeforeCheckout() | CleanCheckout() | 
        CloneOption(shallow: boolean, noTags: boolean, reference: String, timeout: int, depth?: int, honorRefspec?: boolean) | 
        DisableRemotePoll() | GitLFSPull() | IgnoreNotifyCommit() | LocalBranch(localBranch: String) | MessageExclusion(excludedMessage: String) | 
        PathRestriction(includedRegions: String, excludedRegions: String) | PerBuildTag() | 
        PreBuildMerge(options: UserMergeOptions(mergeTarget: String, fastForwardMode?: GitPluginFastForwardMode[FF, FF_ONLY, NO_FF], mergeRemote?: String, mergeStrategy?: Strategy[DEFAULT, RESOLVE, RECURSIVE, OCTOPUS, OURS, SUBTREE, RECURSIVE_THEIRS])) | 
        PruneStaleBranch() | RelativeTargetDirectory(relativeTargetDir: String) | ScmName(name: String) | 
        SparseCheckoutPaths(sparseCheckoutPaths: SparseCheckoutPath(path: String)[]) | 
        SubmoduleOption(disableSubmodules: boolean, recursiveSubmodules: boolean, trackingSubmodules: boolean, reference: String, timeout: int, parentCredentials: boolean) | 
        UserExclusion(excludedUsers: String) | UserIdentity(name: String, email: String) | WipeWorkspace()}[])

Upvotes: 5

Views: 12123

Answers (1)

Szymon Stepniak
Szymon Stepniak

Reputation: 42174

You see this error, because branches key needs to hold a map nested in a list. So it should be:

branches: [[name: '*/master']]

instead

branches: [name: '*/master']

Source: https://jenkins.io/doc/pipeline/steps/workflow-scm-step/#code-checkout-code-general-scm

Full stage then looks like this:

stage('Checkout') {
    steps {
        checkout([$class: 'GitSCM', 
            branches: [[name: '*/master']], 
            doGenerateSubmoduleConfigurations: false, 
            extensions: [[$class: 'CleanBeforeCheckout'], 
                [$class: 'RelativeTargetDirectory', relativeTargetDir: 'targetDir']], 
            submoduleCfg: [], 
            userRemoteConfigs: [[credentialsId: 'jenkinsserviceaccount',
                url: 'https://bitbucket.company.net/scm/moak/myTestRepo.git']]])
    }
}

Regarding the error you see - workflow plugin uses Groovy's ability to cast Map to another type. It works if all map keys map to a class fields correctly, e.g. they have to store the same type. When branches stores a Map instead List<Map>, the whole map cannot be cast to an object that represents SCM configuration.

Upvotes: 5

Related Questions