GoogleCloudPlatform / app-gradle-plugin

The library has moved to https://github.com/GoogleCloudPlatform/appengine-plugins/tree/main/app-gradle-plugin

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot use plugin tasks due to "org.gradle.api.tasks.bundling.Jar.getArchivePath()" because "jar" is null

marceloverdijk opened this issue · comments

I've a minimal Spring Boot application using Java 17 and I'm trying to get AppEngine Gradle plugin to work...

As documented I have set it up like:

settings.gradle:

pluginManagement {
    repositories {
        gradlePluginPortal()
        mavenCentral()
    }
    resolutionStrategy {
        eachPlugin {
            if (requested.id.id.startsWith("com.google.cloud.tools.appengine")) {
                useModule("com.google.cloud.tools:appengine-gradle-plugin:${requested.version}")
            }
        }
    }
}

build.gradle:

plugins {
	id "java"
	id "com.google.cloud.tools.appengine-appyaml" version "2.4.4"
	id "io.spring.dependency-management" version "1.0.12.RELEASE"
	id "org.springframework.boot" version "2.6.10"
}

group = "com.github.marceloverdijk"
version = "0.0.1-SNAPSHOT"
sourceCompatibility = "17"

ext {
	set("springCloudVersion", "2021.0.3")
	set("springCloudGcpVersion", "3.3.0")
}

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencyManagement {
	imports {
		mavenBom "com.google.cloud:spring-cloud-gcp-dependencies:${springCloudGcpVersion}"
		mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
	}
}

dependencies {
	// implementation "com.google.cloud:spring-cloud-gcp-starter"
	implementation "org.apache.commons:commons-lang3"
	implementation "org.springframework.boot:spring-boot-starter-actuator"
	implementation "org.springframework.boot:spring-boot-starter-jetty"
	implementation("org.springframework.boot:spring-boot-starter-web") {
		exclude module: "spring-boot-starter-tomcat"
	}
	annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
	developmentOnly "org.springframework.boot:spring-boot-devtools"
	testImplementation "org.springframework.boot:spring-boot-starter-test"
}

appengine {
	tools {
                // https://github.com/GoogleCloudPlatform/app-gradle-plugin/issues/431
		cloudSdkHome = "/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk"
	}
	deploy {
		projectId = "GCLOUD_CONFIG"
		version = "GCLOUD_CONFIG"
		promote = true
		stopPreviousVersion = true
	}
}

tasks.named("test") {
	useJUnitPlatform()
}

but when running any GAE tasks I get:

❯ ./gradlew appengineShowConfiguration

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring root project 'aircraft-notifier'.
> Cannot invoke "org.gradle.api.tasks.bundling.Jar.getArchivePath()" because "jar" is null

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 587ms

Even the bootRun tasks now fails:

❯ ./gradlew bootRun

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring root project 'aircraft-notifier'.
> Cannot invoke "org.gradle.api.tasks.bundling.Jar.getArchivePath()" because "jar" is null

If I remove just the appengine { .. } configuration block from build.gradle (so GAE plugin itself still configured) the app starts up again with bootRun...

I've removed the appengine plugin completely and was able to deploy the app using gcloud app deploy.

What version of gradle are you using? This seems related to #382; try running adding jar {} to your configuration.

Ah, I see from the other issue it's Gradle 7.5. Yes, try adding the empty jar configuration to see if that's the same issue.

with the empty jar {} I can run appengineShowConfiguration now.

But appengineDeploy then fails later:

❯ ./gradlew appengineDeploy

> Task :appengineDeploy
Services to deploy:

..
target service account:      [App Engine default service account]


Beginning deployment of service [default]...
Created .gcloudignore file. See `gcloud topic gcloudignore` for details.
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 1 file to Google Cloud Storage                 ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...
.........................................................................................................................failed.
ERROR: (gcloud.app.deploy) Error Response: [9] Cloud build 0026a2d5-195a-4ec3-bfaa-8e818f985d7a status: FAILURE
did not find any jar files with a Main-Class manifest entry

What if you call ./gradlew clean bootJar appengineDeploy?

I think a thin jar might be getting created.

./gradlew clean bootJar appengineDeploy gives:

Beginning deployment of service [default]...
Created .gcloudignore file. See `gcloud topic gcloudignore` for details.
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 1 file to Google Cloud Storage                 ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...
......................................................................................................................failed.
ERROR: (gcloud.app.deploy) Error Response: [9] Cloud build 6f3721f3-a1b4-4942-b6a2-9bc9ef544344 status: FAILURE
did not find any jar files with a Main-Class manifest entry

Maybe this is bc Boot generates 2 jars , 1 normal jar and 1 plain jar.
The plain one can be disabled as documented here: https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#packaging-executable.and-plain-archives

So adding:

tasks.named("jar") {
	enabled = false
}

Note I had to add this as well when deploying using Cloud Build (gcloud app deploy).

But then ./gradlew clean bootJar appengineDeploy gives:

❯ ./gradlew clean bootJar appengineDeploy
> Task :appengineStage FAILED

FAILURE: Build failed with an exception.

* What went wrong:
A problem was found with the configuration of task ':appengineStage' (type 'StageAppYamlTask').
  - In plugin 'com.google.cloud.tools.appengine-appyaml' type 'com.google.cloud.tools.gradle.appengine.appyaml.StageAppYamlTask' property 'stagingExtension.artifact' specifies file '/Users/marceloverdijk/workspace/an/build/libs/an-0.0.1-SNAPSHOT-plain.jar' which doesn't exist.

    Reason: An input file was expected to be present but it doesn't exist.

    Possible solutions:
      1. Make sure the file exists before the task is called.
      2. Make sure that the task which produces the file is declared as an input.

    Please refer to https://docs.gradle.org/7.5/userguide/validation_problems.html#input_file_does_not_exist for more details about this problem.

Ah! Use this appengine configuration: GoogleCloudPlatform/appengine-plugins#1003

Thx that did the trick!

If anyone is interested the reason why jar {} worked, is because it forced Gradle to eagerly create and configure (with nothing) the jar Task. This task is used by:

Jar jar = (Jar) project.getProperties().get("jar");
stageExtension.setArtifact(jar.getArchivePath());

Notice the getProperties().get("jar"), that triggers some magical Groovy path to resolve the property, but since Gradle is lazy, the task is not materialized yet as a property. If this plugin used tasks.named or tasks.getByName directly, then that would look in the right (Task) container and the plugin would not get null.