Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

workspace.jar in gradle build output break the build #54

Closed
3 tasks done
jonatan-ivanov opened this issue Mar 7, 2021 · 7 comments · Fixed by #66
Closed
3 tasks done

workspace.jar in gradle build output break the build #54

jonatan-ivanov opened this issue Mar 7, 2021 · 7 comments · Fixed by #66
Assignees
Labels
type:question A user question

Comments

@jonatan-ivanov
Copy link

jonatan-ivanov commented Mar 7, 2021

What happened?

The base builder (pack config default-builder paketobuildpacks/builder:base) fails on a simple gradle project, with the following output:

BUILD SUCCESSFUL in 17s
5 actionable tasks: 5 executed
unable to invoke layer creator
unable to contribute application layer
unable to resolve artifact
unable to find single built artifact in build/libs/*.[jw]ar, candidates: [/workspace/build/libs/app-info.jar /workspace/build/libs/workspace.jar]
ERROR: failed to build: exit status 1
ERROR: failed to build: executing lifecycle: failed with status code: 145

As you can see the Gradle build was successful, it also produced the jar in build/libs (see: /workspace/build/libs/app-info.jar) but there is another jar next to it: /workspace/build/libs/workspace.jar that was not created by Gradle. So the image build process fails because there are more artifacts.

  • What were you attempting to do?
    I have a sample project, it is just a simple Gradle project with the application plugin. Running pack build app-info fails (assuming that the default-builder is paketobuildpacks/builder:base).

  • What did you expect to happen?
    The expectation would be not having an extra jar in the Gradle build output.

  • What was the actual behavior? Please provide log output, if possible.
    See the eror above.

Build Configuration

  • What platform (pack, kpack, tekton buildpacks plugin, etc.) are you
    using? Please include a version.
pack version                                                                                            
0.17.0+git-d9cb4e7.build-2045
  • What buildpacks are you using? Please include versions.
    The ones discovered and added by paketobuildpacks/builder:base on this sample project

  • What builder are you using? If custom, can you provide the output from pack inspect-builder <builder>?
    paketobuildpacks/builder:base

  • Can you provide a sample app or relevant configuration (buildpack.yml,
    nginx.conf, etc.)?
    sample project

Checklist

  • I have included log output.
  • The log output includes an error message.
  • I have included steps for reproduction.

Workaround

Setting the build artifact manually hides the issue and the build succeeds:
pack build app-info --env 'BP_GRADLE_BUILT_ARTIFACT=build/libs/app-info.jar'

@dmikusa
Copy link
Contributor

dmikusa commented Apr 13, 2021

Sorry, I can't reproduce this with your test app.

I'm running: pack build apps/app-info --env 'BP_JVM_VERSION=16' --env 'BP_GRADLE_BUILD_ARGUMENTS=--no-daemon assemble' and I can see it using $BP_GRADLE_BUILT_ARTIFACT build/libs/*.[jw]ar which is the default, but there is only one JAR in that folder so it just works.

I don't know where the workspace.jar file would be coming from. I do vaguely recall seeing something like this before when I was building with the Spring Music app and running ./gradlew clean locally fixed it.

Are you still seeing this issue? Does running a clean locally help? Any ideas where workspace.jar is coming from, I don't recognize that file. Thanks

@dmikusa dmikusa self-assigned this Apr 13, 2021
@dmikusa dmikusa added the type:question A user question label Apr 13, 2021
@jonatan-ivanov
Copy link
Author

jonatan-ivanov commented Apr 13, 2021

The app has changed a little since then (Gradle 7.0 migration) but I can still repro the issue.

If I build the artifacts:
docker rmi apps/app-info:latest; ./gradlew clean assemble && pack build apps/app-info
it fails.

But if I just clean the artifacts:
docker rmi apps/app-info:latest; ./gradlew clean && pack build apps/app-info
it works.

I have no idea where the workspace.jar is coming from but it seems having a jar in the build/libs folder causes this.
If I create the artifacts but I delete the jar, it works:
docker rmi apps/app-info:latest; ./gradlew clean assemble && rm build/libs/app-info.jar && pack build apps/app-info

If I fake the jar: touch build/libs/app-info.jar:

unable to invoke layer creator
unable to contribute application layer
unable to resolve artifact
unable to investigate /workspace/build/libs/app-info.jar
unable to open /workspace/build/libs/app-info.jar
zip: not a valid zip file

so the buildpack definitely cares about my local jar, I don't get why.

If I build the jar:

unable to invoke layer creator
unable to contribute application layer
unable to resolve artifact
unable to find single built artifact in build/libs/*.[jw]ar, candidates: [/workspace/build/libs/app-info.jar /workspace/build/libs/workspace.jar]

@scottfrederick
Copy link

/build/libs/workspace.jar is the output from the Gradle build process in the CNB container. The project files are copied to the build container into the /workspace directory, and Gradle uses the name of the project root dir as the default artifact name. The /build/libs/app-info.jar file is copied into the build container by pack build and left untouched.

Adding this config to build.gradle in the sample project fixes the problem by forcing the archive name to be the same in both the local build and the container build:

jar {
    archiveBaseName.set("app-info")
    ...
}

I'm not sure what the Gradle buildpack should do about this, short of cleaning the /build directory.

@jonatan-ivanov
Copy link
Author

Makes perfect sense, I should have seen this coming. 😄 Can I have a few questions around this behavior?

copying the build folder

The project files are copied to the build container into the /workspace directory

Why is the build folder copied? It is not a project file but the build output folder. This can also cause other issues if there are stale files there that can somehow affect the build output. I guess BP_GRADLE_BUILD_ARGUMENTS=--no-daemon clean assemble should also solve the issue.

What do you think, should part of this issue be fixed by ignoring the Gradle build output folder during copying
(fyi: the build output folder can be changed in the build config, so it can be tricky) or by including clean in the list of executed tasks (I think have a connecting issue: #55)?

renaming the root project

... and Gradle uses the name of the project root dir as the default artifact name.

I guess setting rootProject.name in settings.gradle would be the best way to fix this. This behavior (buildpacks and gradle together) can lead to a whole other can of worms since the root project name can be different if the project is built in a container and a ton of things can use the root project name (e.g.: Manifest file).
Is this something buildpacks can fix for the users by either:

  • enforcing (failing) if it is not set
  • setting it if it is not set (can be tricky)
  • using the same folder name instead of workspace

jonatan-ivanov added a commit to jonatan-ivanov/app-info that referenced this issue Apr 14, 2021
@scottfrederick
Copy link

scottfrederick commented Apr 14, 2021

Why is the build folder copied?

The pack CLI has no idea what kind of project is being built. It could be Java with Maven or Gradle, or it could be Go, Ruby, Node, or just static web content. pack uploads everything in the target path and leaves it to buildpacks to sort out what's there. It's not reasonable for it to know enough about the project to filter content being uploaded.

I guess setting rootProject.name in settings.gradle would be the best way to fix this.

I think that's the most common case. rootProject.name is set if you generate a project using gradle init or Spring Initialzr, which is likely why more users haven't encountered a problem like this.

@dmikusa
Copy link
Contributor

dmikusa commented Apr 14, 2021

Why is the build folder copied?

+1 to what @scottfrederick said here. I would also add that you can include a project.toml file in the root of your project and tell pack build what files to skip, it's like .gitignore but in TOML.

https://buildpacks.io/docs/app-developer-guide/using-project-descriptor/#example

Ex:

[build]
exclude = [
    "/README.md",
    "bash-script-buildpack"
]

What do you think, should part of this issue be fixed by ignoring the Gradle build output folder during copying
(fyi: the build output folder can be changed in the build config, so it can be tricky) or by including clean in the list of executed tasks (I think have a connecting issue: #55)?

I would have to look into this one more. My fear of adding clean would be that you'd wipe out your cache. The first time you build a lot more work happens and the buildpacks cache that so subsequent runs are much faster. If we also include clean, I suspect that those subsequent runs are going to have to redo work unnecessarily. Again, I'm not certain. I'd have to try it, but that's my guess.

using the same folder name instead of workspace

I don't believe this is possible. /workspace is part of the buildpack spec.

setting it if it is not set (can be tricky)

I'm not sure about this. I don't know where we'd pull a name from. The outer directory where Gradle get's the name from locally never makes it into the build container. The project.toml file might be an option as it contains some metadata, but if you have that file you may as well throw in the excludes block and then your local build files won't be included.

enforcing (failing) if it is not set

I'm not sure we'd have to go this far, it already fails. Plus, there can be cases where it's OK to build workspace.jar and use that. I don't think I hit this when I tried to reproduce cause I didn't build locally first. What I can certainly do though is improve the error messages.

Presently you'll see:

unable to find single built artifact in build/libs/*.[jw]ar, candidates: [/workspace/build/libs/app-info.jar /workspace/build/libs/workspace.jar]

I could change it to something like:

unable to find single built artifact in build/libs/*.[jw]ar, candidates: [/workspace/build/libs/app-info.jar /workspace/build/libs/workspace.jar]. If this is unexpected, please try setting `rootProject.name` in `settings.gradle` or add a project.toml file and exclude the `build/` directory. See https://buildpacks.io/docs/app-developer-guide/using-project-descriptor/.

Does that seem like a reasonable path forward?

@jonatan-ivanov
Copy link
Author

@scottfrederick @dmikusa-pivotal Makes sense, thanks for the answers.
I think the proposed change looks good, it could solve the issue for the users who bump into this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:question A user question
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants