MavenPublication cannot find Components on Gradle 6.5.1

Hi there. I am trying to configure a generalized plugin for publishing.
I had a working example from gradle 2.14.1 but this does not carry over too well to gradle 6.5.1

So I read a lot and to my knowledge everything should be working correctly. However executing a build (even without actually executing the publishing task) leads to an error that google finds no answer for.

Specifically, the following Exception is thrown:
groovy.lang.MissingPropertyException: Could not get unknown property 'components' for object of type org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication.

I am at a complete loss why that is. Initially, i thought it might have a connection to the fact that the project throwing this applies the war plugin, but it also uses java which should work, to be sure, I added an extra if checking for presence of war plugin and, if true, use components.web over components.java.
The block in question is currently this:

publications {
  maven(org.gradle.api.publish.maven.MavenPublication) {
    if (project.plugins.hasPlugin('war')) {
      from components.web
    } else if (project.plugins.hasPlugin('java')) {
      from components.java
    }
    afterEvaluate {
      groupId = project.group
      artifactId = project.name
      version = project.version
    }
    if (project.plugins.hasPlugin('spring-boot')) {
      pom {
        parent {
          groupId "org.springframework.boot"
          artifactId "spring-boot-starter-parent"
          version "${project.versions.springBoot}"
        }
      }
    }
  }
}              

the block consistently moves to evaluating components.web, when switching order, components.java is evaluated, and in both cases, components property can not be found.

Any help would be greatly appreciated.

You might need to provide a more complete example that reproduces the problem. The code provided works as expected when added where it belongs in a working Gradle 6.5.1 project, so there’s something impactful that’s not captured here.

Sorry for taking such a long time to reply.
The problem here is, of course, that the project is not open source and I cannot post too much information, so creating a reproducible example is rather difficult here, as is giving exact code samples.

Also not so simple: untangling the plugin code, as it basically is a mashup of several different plugins.

If you (or anyone) can hazard a guess at what might potentially cause this, that would already be a big help.
What I think I can safely show is basically this from the upload-part of the plugin:

        project.plugins.apply('maven-publish')
        project.configurations { deployerJars }
        project.dependencies { deployerJars "org.apache.maven.wagon:wagon-ssh:2.2" }
        def canUpload = project.hasProperty(ARTIFACTORY_USERNAME) && project.hasProperty(ARTIFACTORY_PASSWORD)
        project.publish.onlyIf({canUpload})

basically this part is defined before the block stated in the original post, followed by an evaluation of canUpload to define which repository URL is to be sed, which looks similar to this:

if (canUpload) {
  repositories {
    maven {
      def repositoryReleases
      def repositorySnapshots
      repositoryReleases = ... //ternary to decide on value depending on configured properties
      repositorySnapshots = ... // also ternary depending on properties
      url = project.version.endsWith('SNAPSHOT') ? repositorySnapshots : repositoryReleases
      credentials {
        username ...
        password ...
      }
    }
  }
}

But I don’t see how this could affect the publish-block before.
Furthermore, the plugin manually defines the filename like this:

project.allprojects.each { current ->
  current.afterEvaluate {
    def methods = [...]
    methods.each { method ->
      try {
        current."${method}" {
          doFirst {
            archiveFileName = ...
          }
        }
      }
    }
  }
}

We also force UTF-8 on all projects with a JavaCompile Type Task, set or replace specific properties via gradle, force source and targetCompatibility to 1.8, and define a formatter task.

These actions are among the list of suspects that I have, as other sub-plugins only define task execution dependencies (like “run tests before calling sonar”) or the like.

So, after a lot of trying, I was able to produce the following results

Project structure

test-java-multiproject
|-  test-java-multiproject-api
\- test-java-multiproject-app

declaring build.gradle in test-java-multiproject-api like this

plugins {
    id 'java-library'
}

dependencies {
    compile 'org.apache.commons:commons-lang3:3.11'
}

and in test-java-multiproject-app like this

plugins {
    id 'java'
}
dependencies {
    compile project(':test-java-multiproject-api')
    testCompile ('junit:junit:4.13')
}

working example

using build.gradle in main project like this

buildscript {
	repositories {
		maven { url this.getAt('repositoryDependency') }
	}
}
allprojects { 
	apply plugin:'maven-publish'
	configurations {
		deployerJars
	}
	dependencies {
		deployerJars "org.apache.maven.wagon:wagon-ssh:2.2"
	}
	publishing {
		publications {
			maven(org.gradle.api.publish.maven.MavenPublication) {
				groupId = project.group
				artifactId = project.name
				version = project.version
				if (project.plugins.hasPlugin('java')) {
					from components.java
				}
				if (project.plugins.hasPlugin('spring-boot')) {
					pom {
						parent {
						groupId "org.springframework.boot"
						artifactId "spring-boot-starter-parent"
						version "${project.versions.springBoot}"
						}
					}
				}
			}
		}
		repositories {
			maven {
				def repositoryReleases
				def repositorySnapshots
				
				repositoryReleases = project.hasProperty('repositoryReleases')
					? project.getAt('repositoryReleases')
					: 'http://localhost:8081/artifactory/libs-releases-local'
				repositorySnapshots = project.hasProperty('repositorySnapshots')
					? project.getAt('repositorySnapshots')
					: 'http://localhost:8081/artifactory/libs-snapshots-local'
				url = project.version.endsWith('SNAPSHOT')
					? repositorySnapshots
					: repositoryReleases
				credentials {
					credentials {
						username project.getAt('artifactoryUsername')
						password project.getAt('artifactoryPassword')
					}
				}
			}
		}
	}
	repositories {
		maven {
			url this.getAt('repositoryDependency')
		}
	}
}

subprojects {
    version = '1.0'
}

using any task - inclusing publish - works as intended.

broken example

Changing the main buld.gradle to

apply plugin: 'my-plugin'

buildscript {
	repositories {
		maven { url this.getAt('repositoryDependency') }
	}
	dependencies {
		classpath("my:plugin:0.9.9-SNAPSHOT")
	}
}

allprojects { 
	repositories {
		maven {
			url this.getAt('repositoryDependency')
		}
	}
}

subprojects {
    version = '1.0'
}

and applying my-plugin, which looks llike this:

class UploadPlugin implements Plugin<Project> {
	void apply(Project project) {
		project.allprojects.each { curProject ->
			curProject.afterEvaluate{
				if(curProject.plugins.hasPlugin(JavaPlugin)){
					applyUpload(curProject)
				}
			}
		}
	}

	void applyUpload(Project project){
        project.plugins.apply('maven-publish')
        project.configurations { deployerJars }
        project.dependencies { deployerJars "org.apache.maven.wagon:wagon-ssh:2.2" }
        def canUpload = project.hasProperty('uploadable')
        project.publishing {
            publications {
                maven(org.gradle.api.publish.maven.MavenPublication) {
                    groupId = project.group
                    artifactId = project.name
                    version = project.version
                    if (project.plugins.hasPlugin('java')) {
                        from components.java
                    }
                    if (project.plugins.hasPlugin('spring-boot')) {
                        pom {
                            parent {
                                groupId "org.springframework.boot"
                                artifactId "spring-boot-starter-parent"
                                version "${project.versions.springBoot}"
                            }
                        }
                    }
                }
            }
            if (canUpload) {
                repositories {
                    maven {
                        def repositoryReleases
                        def repositorySnapshots
                        
                        repositoryReleases = project.hasProperty('rel')
                            ? project.getAt(rel)
                            : 'url1'
                        repositorySnapshots = project.hasProperty('sna')
                            ? project.getAt('sna')
                            : 'url2'
                        url = project.version.endsWith('SNAPSHOT')
                            ? repositorySnapshots
                            : repositoryReleases
                    }
                }
            }
        }
    }
}

consistently leads to the following build fail when using
gradle clean assemble test

* What went wrong:
A problem occurred configuring project ':test-java-multiproject-api'.
> Could not get unknown property 'components' for object of type org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication.

As far as I know, both situations should be roughly the same. The plugin was compiled with the same version as the current project is being executed.
If I ever find out how to package the plugin itself with the project and apply it, I will gladly provide it, however right now I’d have to release the entire plugin which I am definitely not allowed to do.

If this helps anyone in reproducing and helping, please tell me. Thanks a lot in advance.