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
[JENKINS-43900] Update to 2.X parent POM #5
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🐛 for getType()
check. It is required to ensure it was not a migration logic before decoupling of the plugin
src/findbugs/excludesFilter.xml
Outdated
@@ -25,4 +25,16 @@ | |||
<Match> | |||
<Class name="~.*\.Messages"/> | |||
</Match> | |||
<Match> | |||
<Bug pattern="RV_RETURN_VALUE_IGNORED_BAD_PRACTICE"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use @SuppressFBWarnings()
instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed but, out of curiosity, why is that preferable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So that you can write a clear justification
in every case.
} else { | ||
return new InputStreamReader(getLogInputStream(), getCharset()); | ||
} | ||
return new InputStreamReader(getLogInputStream(), getCharset()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it is correct, but OK
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getCharset() is already checking for nullability and returning default charset in that case.
@@ -158,7 +158,7 @@ public String getGroupId() { | |||
*/ | |||
@NonNull | |||
public String getType() { | |||
return type == null ? DEFAULT_TYPE : type; | |||
return type; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🐛 I am pretty sure it was a migration logic. Should be replaced by readResolve
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can be missing something, but type is being set in the constructor, where the null check is already done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Object deserialization does not involve the constructor. So, if somebody migrates old data, this field can be probably null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right so I am reverting this. Thanks @oleg-nenashev
This pull request originates from a CloudBees employee. At CloudBees, we require that all pull requests be reviewed by other CloudBees employees before we seek to have the change accepted. If you want to learn more about our process please see this explanation. |
@@ -36,6 +37,7 @@ | |||
/** | |||
* @author stephenc | |||
*/ | |||
@SuppressFBWarnings(value = "SE_BAD_FIELD") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? This certainly looks like a bug to me. AbstractBuild
cannot be serialized. So either make the field transient
, or remove implements Serializable
if no one is actually serializing it, or explain why this code is not doing what it looks like.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed Serializable as it would not be working up to now.
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
/** | ||
* @author stephenc | ||
*/ | ||
public class DeployEvent implements Serializable { | ||
public class DeployEvent { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a weight-in from the maintainer. The class is definitely not serializable in the current implementation. But removal of the interface breaks binary compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess nobody was serializing this because there would be issues raised. But a confirmation from the maintainer would be great for sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm in agreement with @oleg-nenashev . Even though removing it is harmless it would break binary compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@christ66 so then supressing back the Findbugs error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just remove the interface
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah if it is not actually serializable, then removing the interface does not break anything that was not already broken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -157,6 +158,7 @@ public String getGroupId() { | |||
* @return the type of artifact to match. | |||
*/ | |||
@NonNull | |||
@SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", justification = "Might be null if serialized") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"deserialized", but ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks ok to me... seems like a lot of fussing over nothing... though I have given up maintaining this plugin as E_TO_MANY_PLUGINS
@oleg-nenashev @jglick @christ66 @olamy once Stephen has approved this, are you fine with this getting merged? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incorrect use of Remoting.
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
/** | ||
* @author stephenc | ||
*/ | ||
public class DeployEvent implements Serializable { | ||
public class DeployEvent { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah if it is not actually serializable, then removing the interface does not break anything that was not already broken.
@@ -36,7 +36,7 @@ | |||
/** | |||
* Since we allow token expansion, we must provide a default Maven path -- in | |||
* case they are running on a master without any Mavens. | |||
* <p/> | |||
* <p></p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually wrong. Just use
<p>
@@ -232,7 +234,7 @@ public void log(String message) { | |||
throw new DeployException("Deployment hosts of type " + configuration.getClass() + " are unsupported"); | |||
} | |||
|
|||
public static class FingerprintDecorator implements Callable<DeployedApplicationLocation, IOException> { | |||
public static class FingerprintDecorator extends MasterToSlaveCallable<DeployedApplicationLocation, IOException> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think this is true. FingerprintingWrapper
has code which apparently calls it from the agent side, if that callable was running remotely. And its body calls Hudson.getInstance()
without a null check, confirming that it is intended to be run on the master side. Thus it should be a SlaveToMasterCallable
.
But before you make such a change you would need to review its implementation carefully to ensure that no malicious arguments could possibly cause any harm. That seems unlikely, since the agent could pass any md5sum
it likes, mangling fingerprints of some unrelated artifact. Which means that really FingerprintDecorator
needs to be deleted, and FingerprintingWrapper
needs to be reworked so that any information about fingerprints is simply return
ed, to be handled by its caller (after any necessary sanity checks). That in turn means understanding the call points in the two Engine.process
overloads. The one taking FilePath
is called from perform
in what is clearly a master context (because it is calling build.getWorkspace()
, and a Run
can only exist on master); thus the other overload must also be called from master. Thus it is the process
methods which would need to add suitable DeployedApplicationFingerprintFacet
s; perhaps FingerprintingWrapper
needs to be returning a pair of DeployedApplicationLocation
and md5sum
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jglick So let's see if I follow you. You mean that:
- The engine.process() is executed in master.
- It calls the wrapper, which is executed in the agent.
- This one calls the decorator, which is executed in the master.
- Again in the wrapper, eventually it returns this information to the master.
And you think such "travel" to decorate could be avoided by returning what's necessary in the wrapper and just using it in the process() method. Is that it?
If so, what it's not clear to me is if you think this is something to improve or something that you think that is required. Because if the first one, I would prefer to tackle that in another PR to move this forward and not to increase the size of this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jglick ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that it?
Yes.
if you think this is something to improve or something that you think that is required
I think fixing this is required. Certainly the PR as it currently stands is incorrect. Anyway it should be a pretty small refactoring; I am happy to offer a suggested commit if you are unsure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Last commit should make it. Please let me know if you think something is not appropriate.
@@ -119,7 +119,10 @@ protected boolean knows(@NonNull Class<? extends AbstractProject> jobType) { | |||
*/ | |||
@Override | |||
public Run<?, ?> getLastSuccessfulBuild(AbstractProject<?, ?> project) { | |||
return CapabilitiesResolver.getLastDeployableBuild(PromotionProcess.class.cast(project).getRootProject()); | |||
if (project != null) { | |||
return CapabilitiesResolver.getLastDeployableBuild(PromotionProcess.class.cast(project).getRootProject()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pointless use of Class.cast
(should never be used with a constant receiver). Just
(PromotionProcess) project
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much better, thanks!
@stephenc you might want to take a look since this is your code IIRC
@@ -205,6 +206,33 @@ public DeployedApplicationLocation process(File applicationFile, T target) throw | |||
} | |||
} | |||
|
|||
private DeployedApplicationLocation addToFacects(AbstractMap.SimpleEntry<String, DeployedApplicationLocation> pair) throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
} | ||
|
||
public static class FingerprintingWrapper extends MasterToSlaveFileCallable<DeployedApplicationLocation> { | ||
public static class FingerprintingWrapper extends MasterToSlaveFileCallable<AbstractMap.SimpleEntry<String, DeployedApplicationLocation>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clearer to use Map.Entry<…>
as the declared type
@@ -181,7 +180,8 @@ public boolean perform() throws Throwable { | |||
public DeployedApplicationLocation process(FilePath applicationFile, T target) throws DeployException { | |||
try { | |||
FingerprintingWrapper actor = new FingerprintingWrapper(newDeployActor(target), listener); | |||
return applicationFile.act(actor); | |||
AbstractMap.SimpleEntry<String, DeployedApplicationLocation> pair = applicationFile.act(actor); | |||
return this.addToFacects(pair); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arguably more readable if pair
is inlined (so the verbose type need not be mentioned)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely! Changed.
|
||
if (!NO_MD5.equals(md5sum)) { | ||
Jenkins j = Jenkins.getInstance(); | ||
if (j == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can use getActiveInstance
in suitable core versions (later it is back to getInstance
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not available in 1.580.1
if (instance != null) { | ||
return decorator.call(); | ||
} else { | ||
Channel current = Channel.current(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any deletion of a call to Channel.current()
is a happy day!
} catch (Exception e) { | ||
listener.error("[cloudbees-deployer] Could not record fingerprint association"); | ||
// e.printStackTrace(listener.getLogger()); | ||
} catch (LinkageError e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very possibly obsolete.
: "Can only have a null Jenkins instance if on the other end of a channel"; | ||
return current.call(decorator); | ||
} | ||
return new AbstractMap.SimpleEntry<String, DeployedApplicationLocation>(md5sum, location); | ||
} catch (Exception e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The try
-catch
could probably be deleted and the caller made to handle any of the usual exceptions, as it probably already is. I suspect this was here in case the callback to master failed, which is now an obsolete condition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I have removed them as they are being captured in the process() method.
String md5sum = Util.getDigestOf(fis); | ||
return new AbstractMap.SimpleEntry<String, DeployedApplicationLocation>(md5sum, location); | ||
} finally { | ||
IOUtils.closeQuietly(fis); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just
fis.close();
suffices
@oleg-nenashev @stephenc @christ66 any extra comment here? |
@@ -232,76 +261,26 @@ public void log(String message) { | |||
throw new DeployException("Deployment hosts of type " + configuration.getClass() + " are unsupported"); | |||
} | |||
|
|||
public static class FingerprintDecorator implements Callable<DeployedApplicationLocation, IOException> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also incompatible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How so?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allows us to delete this nonsense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not ready to approve it due to the incompatible changes like FingerprintDecorator
class removal.
But I leave the decision to maintainers. If the current version gets merged, I just strongly recommend to release it as a new major version (2.0
)
I do not see any incompatibilities here and see no need for a 2.0 version. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems ok, but I haven't looked at this plugin in ages
@@ -157,6 +158,7 @@ public String getGroupId() { | |||
* @return the type of artifact to match. | |||
*/ | |||
@NonNull | |||
@SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", justification = "Might be null if deserialized") | |||
public String getType() { | |||
return type == null ? DEFAULT_TYPE : type; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could remove the fb warning suppression with StringUtils.defaultString(type, DEFAULT_TYPE)
@stephenc thanks. @olamy @jglick @oleg-nenashev do you think this could be merged (and released) now? |
@oleg-nenashev why do you think the changes are incompatible? The class is used only internally, and it's behaviour has been maintained. |
|
Of course not, but there is no remotely plausible use case for this class outside its plugin. |
So is there anything I can do to move this forward? |
I think @stephenc is the maintainer. |
@stephenc ping. Could you please review (and merge if appropriate) this? |
@reviewbybees done |
@stephenc again |
@jglick can someone else roll the release or do you need me to? |
Any intentions to release this? |
I'd guess it will happen soon after #7 |
JENKINS-43900
@reviewbybees @olamy @stephenc @jglick @kwhetstone @andresrc