Use Gradle Property and Provider to enable lazy evaluation for jib.to.image and jib.to.tags#2739
Conversation
chanseokoh
left a comment
There was a problem hiding this comment.
Aside from writing unit tests, have you manually tested if this works?
jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/TargetImageParameters.java
Outdated
Show resolved
Hide resolved
jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/TargetImageParameters.java
Outdated
Show resolved
Hide resolved
jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/TargetImageParameters.java
Show resolved
Hide resolved
jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/TargetImageParameters.java
Outdated
Show resolved
Hide resolved
|
chanseokoh
left a comment
There was a problem hiding this comment.
Just went over it briefly as a draft.
jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/TargetImageParameters.java
Show resolved
Hide resolved
| } | ||
|
|
||
| public void setImage(Provider<String> image) { | ||
| if (image != null) { |
There was a problem hiding this comment.
I speculate that we won't need this null check.
There was a problem hiding this comment.
hm removing this check is resulting in an UnexpectedBuildFailure with the message, Cannot set the value of a property using a null provider in places where the target image value is not set. (For example,
There was a problem hiding this comment.
Aha, looks like Gradle prefers this method signature over String. If that's the case, I think it should be
| if (image != null) { | |
| if (image == null) { | |
| this.image = null; | |
| } else { | |
| this.image.set(image); | |
| } |
There was a problem hiding this comment.
Ah, exactly! You're right, when jib.to.image is set to null then Gradle prefers this method. With the if (image != null) checker, we are currently returning the message Missing target image parameter, perhaps you should add a 'jib.to.image' configuration parameter to your build.gradle... if jib.to.image is not specified, which seems like expected behavior. I could be missing something here but why do we want to make the Property be null instead of not just not setting a value for it?
There was a problem hiding this comment.
Good question.
From the general API perspective, irrelevant of Jib: let's say a Java developer is using some Java library which has Person.setEmail(String). It's an optional property, and by default getEmail() returns null. Let's say the developer does
// prints out "no email given" by default
System.out.println(person.getEmail() == null ? "no email given" : person.getEmail());
person.setEmail("foo@example.com");
person.setEmail(null);
System.out.println(person.getEmail() == null ? "no email given" : person.getEmail());Then, which would be reasonable for the last println() to print: no email given or foo@example.com? Of course, it may depend on the situation, but in this case, I expect setEmail(null) to clear the previous value and make the property "missing"; it is counter-intuitive it becomes a no-op.
Also note that jib.to.image is basically an optional property (as indicated by the @Optional annotation). Of course, it is required when pushing to a remote registry (jib:build), and it will say "Missing target image parameter." However, it isn't required when pushing to a local Docker daemon (jib:dockerBuild); in this case, Jib will auto-pick some name for it.
But, before we add the null check, I'd like to verify Gradle always calls setImage(null) even when jib.to.image is simply missing (not configured) rather than when jib.to.image is explicitly set to null. Reading https://github.com/GoogleContainerTools/jib/pull/2739/files#r485907745, it looks like this is only when explicitly setting jib.to.image to null. In that case, I don't think we need the null check actually; I think we can just fix the failing test.
There was a problem hiding this comment.
Thank you so much for the detailed explanation!
And with regards to the last point about https://github.com/GoogleContainerTools/jib/pull/2739/files#r485907745, the issue only occurs when jib.to.image is explicitly set to null. I believe the tests that were failing set jib.to.image to System.getProperty("_TARGET_IMAGE") and didn't initialize _TARGET_IMAGE? Because System.getProperty(String key) returns null if there is no property with that key.
There was a problem hiding this comment.
Yeah, that makes sense. I think we don't actually need a null check; we can just fix the test, e.g., setting _TARGET_IMAGE to "ignored."
jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/TargetImageParameters.java
Outdated
Show resolved
Hide resolved
| } | ||
|
|
||
| public void setImage(Provider<String> image) { | ||
| if (image != null) { |
There was a problem hiding this comment.
Aha, looks like Gradle prefers this method signature over String. If that's the case, I think it should be
| if (image != null) { | |
| if (image == null) { | |
| this.image = null; | |
| } else { | |
| this.image.set(image); | |
| } |
| } | ||
|
|
||
| public void setTags(Provider<Set<String>> tags) { | ||
| this.tags.set(tags); |
There was a problem hiding this comment.
In light of https://github.com/GoogleContainerTools/jib/pull/2739/files#r485008215, I wonder if we need a null check. Can you run a manual test and see which of the two setTags() gets called?
There was a problem hiding this comment.
That is a good idea. So unlike the case with the image, setting jib.to.tags=null is resulting in GroovyRuntimeException with Ambiguous method overloading...Cannot resolve which method to invoke for [null] due to overlapping prototypes between where one setTags is not preferred over the other. The issue occurs when only setTags(Provider<Set<String>>) is present, which is when setting jib.to.tags=null results in the Cannot set the value of property using null provider message.
There was a problem hiding this comment.
Passing in a set or provider<set> that contains null seems to resulting in NPE so I think we need to handle that?
There was a problem hiding this comment.
Hmm... I think we should be fine as long as nothing breaks when jib.to.tags is missing (not configured). People shouldn't explicitly set it to null anyway. That said, I now wonder the test failure you mentioned in https://github.com/GoogleContainerTools/jib/pull/2739/files#r485008215 is when you explicitly set the property to null rather than when it's missing. If former, I don't think we need the null check there either.
Passing in a set or provider that contains null seems to resulting in NPE so I think we need to handle that?
Let's file an issue for that. It basically sounds like an orthogonal issue we don't want to mix in here.
There was a problem hiding this comment.
Right that's a good point. I filed an issue for it in #2760
jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/TargetImageParameters.java
Show resolved
Hide resolved
jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/TargetImageParameters.java
Show resolved
Hide resolved
chanseokoh
left a comment
There was a problem hiding this comment.
Looks good to me. I'll let @loosebazooka approve this.
jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/skaffold/FilesTaskV2Test.java
Outdated
Show resolved
Hide resolved
jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/skaffold/SyncMapTaskTest.java
Outdated
Show resolved
Hide resolved
@loosebazooka so we decided to accept |
| public class HelloWorld { | ||
|
|
||
| public static void main(String[] args) throws URISyntaxException, IOException { | ||
| try (Reader reader = |
There was a problem hiding this comment.
If you're not using the contents of this file to do anything special, just a simple System.out.println("Hello world") is probably sufficient.
| @Test | ||
| public void testLazyEvalForImageAndTags() { | ||
| try { | ||
| testProject.build(JibPlugin.JIB_EXTENSION_NAME); |
There was a problem hiding this comment.
I think this technically works, but is confusing. Maybe JibPlugin.BUILD_IMAGE_TASK_NAME is more appropriate?
There was a problem hiding this comment.
Ah that makes more sense
| String output = ex.getBuildResult().getOutput().trim(); | ||
|
|
||
| // Regex to parse through image and tag values from build output. | ||
| String cyanWordRegex = "\\u001B\\[36m(.+?)\\u001B\\[0m"; |
There was a problem hiding this comment.
I don't know if this is true, but if you use -Djib.console=plain, it might be easier to read the output, and you can ignore the cyan coloring and stuff?
Also since we already know the image name and tags, could we just use those in the comparison directly instead of extracting them out and then using the Assert at line 404, 405?
There was a problem hiding this comment.
Thanks for the suggestion! Unfortunately, jib.console=plain doesn't display the progress bar but still keeps the cyan coloring:(
Also since we already know the image name and tags, could we just use those in the comparison directly instead of extracting them out and then using the Assert at line 404, 405?
Good point, I just applied the change.
There was a problem hiding this comment.
How about passing --console=plain to Gradle? (Note it is not -D... this time.)
There was a problem hiding this comment.
Hm the cyan coloring still appears when --console=plain is passed to Gradle and when Djib.console=plain is used.
There was a problem hiding this comment.
Ugh, you're right. I see there are a couple things that are always colored.
Containerizing application to Docker daemon as francium25/test...
Built image to Docker daemon as francium25/test
I think we should fix this. Could you file a bug (and also link this issue to get rid of the interim code to handle color)?
There was a problem hiding this comment.
Yup, that's a good idea. I added a TODO with reference to issue #2764.
jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java
Show resolved
Hide resolved
Well the underlying type is
|
Fixes #2727
Usage:
jib.to.imageandjib.to.tagswith Stringvaluethey can do the following:jib.to.image = project.provider{value}orjib.to.tags = project.provider{[value, "tag2"]}