Skip to content

Conversation

@stephenc
Copy link
Member

@stephenc stephenc commented Nov 7, 2016

See JENKINS-39553

@reviewbybees @jenkinsci/code-reviewers


This change is Reviewable

@ghost
Copy link

ghost commented Nov 7, 2016

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.

Copy link
Member

@oleg-nenashev oleg-nenashev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐛 for the undocumented AbstractMethodError in the code, which seems to be a breaking change. Other stuff LGTM excepting NITs


/**
* Called when a {@link GitHubPushTrigger} is about to be removed.
* @deprecated use {@link #onStop(Item)}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add the @Deprecated annotation

@SuppressWarnings("unused")
public FormValidation doCheckHookRegistered(@AncestorInPath Job<?, ?> job) {
Preconditions.checkNotNull(job, "Job can't be null if wants to check hook in monitor");
public FormValidation doCheckHookRegistered(@AncestorInPath Item job) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be useful to add @Restricted when you touch such methods. NIT

*
* @return true if overridden deprecated method
* Looks at the definition of {@link Item} and list up the related github repositories,
* then puts them into the collection.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@since

)) {
// if this impl is legacy, it cannot contribute to non-jobs, so not an error
if (item instanceof Job) {
parseAssociatedNames((Job<?, ?>) item, result);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe put a warning on the FINE level? Just in case somebody needs to debug the compat issue

parseAssociatedNames((AbstractProject<?, ?>) item, result);
}
} else {
throw new AbstractMethodError("you must override the new overload of parseAssociatedNames");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐛 So it will expose the error when somebody uses Predicates like withTrigger e.g. in DefaultPushGHEventSubscriber.#isApplicable(). Instead of returning false this method will start throwing Error after the patch if there is an incompatible contributor. Just if I read it right...

IMHO there should be one of the following fixes:

  • Log warning and do nothing
  • Replace the Error by non-runtime exception and implement correct handling in the upper logic

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this is more a design error in the original API. These methods taking the collection should actually have been protected as they form part of the SPI not the API.

If you have an old implementation, then you will have overridden parseAssociatedNames(Job,Collection) or parseAssociatedNames(AbstractProject,Collection) and thus we delegate to those.

If you have a new implementation, then you are supposed to override parseAssociatedNames(Item,Collection) and if you don't then this exception should blow up in your face and give you the AME.

If we had these SPI methods as protected then we could make parseAssociatedNames(Item,Collection) abstract and use the API methods like parseAssociatedNames(Item) to route through to the implementation of existing extension points... but instead, as this is public API we have to do it this way and we have no way to force new implementations to override parseAssociatedNames(Item,Collection) other than this exception

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also please check the previous implementation of parseAssociatedNames(Job<?, ?> job, Collection<GitHubRepositoryName> result) which threw the exact same exception. All I am doing here is moving the exception throwing from the previously most generic method to the new most generic method.

The exception will only be thrown if you have an implementation that does not override any parseAssociatedNames methods. If this had been designed as an SPI then the implementation methods would be protected and we could have shifted the abstract and used a guard.

To clarify for @KostyaSha this is not a bug just migration of existing pattern

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stephenc only since

*/
public abstract class GHEventsSubscriber implements ExtensionPoint {
private static final Logger LOGGER = LoggerFactory.getLogger(GHEventsSubscriber.class);
private transient Boolean hasIsApplicableItem;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would explicitly add CheckForNull, just for the future

* Returns the elements from this fluent iterable that are instances of the supplied type. The
* resulting fluent iterable's iterator does not support {@code remove()}.
*/
@CheckReturnValue
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@since

return new Predicate<Job>() {
public boolean apply(Job job) {
return triggerFrom(job, clazz) != null;
public static <ITEM extends Item> Predicate<ITEM> withTrigger(final Class<? extends Trigger> clazz) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% sure it's a binary compatible change, same for below. Need to check it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type gets erased. It may cause compiler errors if compiling against the newer API but the erased type is still Predicate

* TODO use standard method in 1.621+
*/
@CheckForNull
public static <T extends Trigger> T triggerFrom(Item item, Class<T> tClass) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@since

* @return runnable to create hooks on run
* @see #createHookSubscribedTo(List)
*/
public Runnable registerFor(final Item item) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@since

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since missing

@stephenc
Copy link
Member Author

stephenc commented Dec 7, 2016

@lanwen can we get this merged and released?

@KostyaSha
Copy link
Member

@stephenc when it will be reviewed and verified

@stephenc
Copy link
Member Author

stephenc commented Dec 7, 2016

@KostyaSha the changes are good, oleg just misunderstood... right now this is required to get the github-branch-source 2.0 release out.

@KostyaSha
Copy link
Member

KostyaSha commented Dec 7, 2016

@stephenc situation is that all existing github plugins was ignored, we also suggested to use shared connection and other things, but your multibranch still inventing own things. Now different stuff is pushed into plugins and we will be forced to maintain it. That's look not very good, my gh plugins fully using github-plugin so i need firstly identify that it wouldn't break anything. github-api-plugin already got portion of sh.. without answers jenkinsci/github-api-plugin@185541a and i already raised questions to jenkinsci board why non-maintainer people making changes into plugin.

@stephenc i will try review as soon as i can 3 am 💤

@stephenc
Copy link
Member Author

stephenc commented Dec 8, 2016

@KostyaSha I am not happy with some of the mess that I have found, e.g. GitHub org folders plugin should never have been released... I'm working on getting these aligned better, but it's a marathon not a sprint.

Copy link
Member

@KostyaSha KostyaSha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oleg's comments are not addressed

@KostyaSha
Copy link
Member

@KostyaSha I am not happy with some of the mess that I have found,

Compare what is done in CB plugins and what exists and working well for a year here https://github.com/KostyaSha/github-integration-plugin (it was under jenkinsci and was planned to go into one powerful github-plugin, but i was forced to go out of jenkins infra).

@stephenc stephenc changed the title [FIXED JENKINS-39533] Make GitHub plugin BuildableItem aware [FIXED JENKINS-39553] Make GitHub plugin BuildableItem aware Dec 8, 2016
@stephenc
Copy link
Member Author

stephenc commented Dec 8, 2016

@KostyaSha said:

Oleg's comments are not addressed

Incorrect, I fixed or added a rationale for every one of oleg's comments

@stephenc
Copy link
Member Author

stephenc commented Dec 8, 2016

FTR this is now blocking releasing Branch API 2.0, so if we could get some progress on a decision it would be super awesome as I have a lot of plugins to juggle getting releases at or near the same time

@KostyaSha
Copy link
Member

And please don't merge branches into branch this complicates search in tree.

@stephenc
Copy link
Member Author

stephenc commented Dec 8, 2016

Sorry merge commit got pushed by accident when I was trying to diagnose the events being missing (thank you fail2ban... though not having these changes was also a culprit, fail2ban was stopping them even getting to my server)

public FormValidation doCheckHookRegistered(@AncestorInPath Job<?, ?> job) {
Preconditions.checkNotNull(job, "Job can't be null if wants to check hook in monitor");
@Restricted(NoExternalUse.class) // invoked from Stapler
public FormValidation doCheckHookRegistered(@AncestorInPath Item job) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename job to item

public static class FromSCM extends GitHubRepositoryNameContributor {
@Override
public void parseAssociatedNames(Job<?, ?> job, Collection<GitHubRepositoryName> result) {
public void parseAssociatedNames(Item job, Collection<GitHubRepositoryName> result) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

job -> item

Copy link
Member

@oleg-nenashev oleg-nenashev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐝 since it does not increase the technical debt. But this Abstract method handling stuff ideally needs to be solved.

@stephenc
Copy link
Member Author

stephenc commented Dec 9, 2016

@oleg-nenashev yes, a correct solution is to use the SPI pattern like I have done in SCM API where the methods that implementers are required to implement are protected and the methods that consumers are supposed to call are public final.

Then when you need to adapt the API/SPI, what you do is have the public final check the current protected abstract and fall back through previous SPI methods. You will be guaranteed to get a match as:

  • A new implementation will not compile unless they implement the current protected abstract
  • An old implementation has to have implemented one of the previous protected abstract that you have now deprecated or they would not have compiled against the old SPI

@stephenc
Copy link
Member Author

stephenc commented Dec 9, 2016

@reviewbybees done

@KostyaSha
Copy link
Member

Have you tried open jenkins global settings?

@stephenc
Copy link
Member Author

@KostyaSha you mean the Caused by: java.lang.NoSuchMethodError: jenkins.model.Jenkins.getActiveInstance()Ljenkins/model/Jenkins; errors because this needs the bump to 1.609 baseline to work with credentials (which is already in master but you didn't want me to include the merge commit?

@KostyaSha
Copy link
Member

I placed new gh plugin version into my test instance and it failed with

target/tmp/webapp/WEB-INF/lib/jenkins-core-1.625.3.jar!/lib/form/rowSet.jelly:47:23: <d:invokeBody> No such property: configuration for class: org.jenkinsci.plugins.github.GitHubPlugin
	at 

@stephenc
Copy link
Member Author

@KostyaSha are you sure that isn't an issue for you anyway with either master or the base version this PR was created against? there is no change in this PR that should create that issue for you

@KostyaSha
Copy link
Member

i'm checking around...

@KostyaSha
Copy link
Member

revert to 1.22.1 works.

@stephenc
Copy link
Member Author

Well this PR is off of 1.22.4 so I claim your issue is outside of the scope of this PR

@KostyaSha
Copy link
Member

1.22.4 also works.

@KostyaSha
Copy link
Member

Caused by: 
java.lang.NoSuchMethodError: com.cloudbees.plugins.credentials.common.StandardListBoxModel.includeEmptyValue()Lcom/cloudbees/plugins/credentials/common/AbstractIdCredentialsListBoxModel;
	at org.jenkinsci.plugins.github.config.GitHubServerConfig$DescriptorImpl.doFillCredentialsIdItems(GitHubServerConfig.java:291)

@stephenc
Copy link
Member Author

Have you upgraded credentials?

Method isApplicable = clazz.getDeclaredMethod("isApplicable", Item.class);
if (isApplicable.getDeclaringClass() != GHEventsSubscriber.class) {
// ok this is the first method we have found that could be an override
// if somebody overrode an inherited method with and `abstract` then we don't have the method
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

override?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

past tense of override is overrode

@KostyaSha
Copy link
Member

Have you upgraded credentials?

seems no, i'm using hpi:run from my plugin and comparing on working variant. So yes, maybe caused by super latest requirement.

@KostyaSha
Copy link
Member

hpi from pr build seems working, looks like something strange in your PR head even after rebase

@KostyaSha
Copy link
Member

Workflow messed all plugins to work with Job that is not suitable in many cases. Now github-plugin should extend to Item. I see no any methods that could be useful for Item. Why top-level hierarchy item should deal with gh?? If this PR about BuildableItem, then it should be BuildableItem . And even in BuildableItem i see no any useful types for storing something useful. There is no properties, actions. Only methods to build and display. So type expansion is under huge question.

AbstractTopLevelItem/AbstractItem at least has actions!

@KostyaSha
Copy link
Member

screenshot 2016-12-12 00 22 24
I reviewed all methods and types. Maybe i see bit more than core provides. I can switch to core sources.

@stephenc
Copy link
Member Author

@KostyaSha this is not about workflow, but about removing the assumption that the only thing that would want to know about events are jobs and that the only things to trigger are Jobs.

For example https://github.com/jenkinsci/cloudbees-folder-plugin/blob/41f1e2d63f8e4ef82bb845a01fc81ea5e427f465/src/main/java/com/cloudbees/hudson/plugins/folder/computed/ComputedFolder.java#L97 is a BuildableItem and may want to listen for events from the event handler in order to generate items based on the changes.

@stephenc
Copy link
Member Author

IMHO we are better allowing the events to be picked up by any generic Item (as that way we can at least mix-in the Item interface rather than relying on the abstract base class.

The trigger should work on anything that is a BuildableItem because that is where a trigger makes sense

@KostyaSha
Copy link
Member

Ideally should be TrigerableItem :/ Though if item wants and subscriber can get. Then ok. Penalty is that now hook iteration will deal with Jenkins.getAllItems() that literally is all items.

@KostyaSha
Copy link
Member

I just fear another brainf.. like Parametrized.JobMixIn that doesn't allow to mock tests because methods needs crazy generics and etc.

abstract method (Item) picks for old binary child abstract(Job) calls, right?

Copy link
Member

@KostyaSha KostyaSha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified manually that hpi doesn't break binary compatibility, though it impossible to run mvn tests against fresh github-plugin automatically

@KostyaSha KostyaSha merged commit bd2e945 into jenkinsci:master Dec 11, 2016
@stephenc
Copy link
Member Author

Thanks for merging. Any estimate on when a release can be cut?

@KostyaSha
Copy link
Member

Fixing different since. Maybe it possible add empty checkstyle in parent pom that will have single @since {TODO/FIXME//} on fail build level?

@KostyaSha
Copy link
Member

released.

@stephenc stephenc deleted the jenkins-39553 branch December 12, 2016 09:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants