Skip to content

Add individual precommit task plugins #56926

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

Merged
merged 17 commits into from
May 20, 2020
Merged

Conversation

rjernst
Copy link
Member

@rjernst rjernst commented May 18, 2020

Each precommit task is currently registered inside the shared
PrecommitTasks class. Having a single class with all precommit tasks
makes individualizing which precommit tasks are needed based on type of
project difficult, where we often just disable somet tasks eg for all qa
projects. This commit creates plugins for each precommit task, and moves
the configuration of the task into each plugin. PrecommitTasks remains
for now, and just delegates to each plugin, but will be removed in a
future change.

Each precommit task is currently registered inside the shared
PrecommitTasks class. Having a single class with all precommit tasks
makes individualizing which precommit tasks are needed based on type of
project difficult, where we often just disable somet tasks eg for all qa
projects. This commit creates plugins for each precommit task, and moves
the configuration of the task into each plugin. PrecommitTasks remains
for now, and just delegates to each plugin, but will be removed in a
future change.
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra (:Core/Infra/Build)

@rjernst rjernst requested a review from mark-vieira May 18, 2020 22:05
@elasticmachine elasticmachine added the Team:Core/Infra Meta label for core/infra team label May 18, 2020
Copy link
Contributor

@breskeby breskeby left a comment

Choose a reason for hiding this comment

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

This is great and definitely the right way to go something is dying in me every time I see a task.enabled = false :)

I wonder if we should rethink the term precommit here as we implies this is ONLY executed pre commit. But all those things should and do also run on CI. In other builds I often saw the term sanityCheck. I'm not saying we need to fix this here as part of that PR but just food for thought / discussion.

/**
* Base plugin for adding a precommit task.
*/
public abstract class PrecommitPlugin implements Plugin<Project> {
Copy link
Contributor

@breskeby breskeby May 19, 2020

Choose a reason for hiding this comment

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

I think it would be better to not extend this Plugin in other PrecommitPlugins but use composition here. So we would have a PreCommit plugin that is applied by all other specific PreCommitPlugins (e.g. the CheckstylePreCommitPlugin). The PreCommitPlugin would only create a 'precommit' task that depends on all tasks of a certain marker type like tasks.withType(PreCommitTask.class). The other specific precommit plugins would only need to ensure that the tasks they create are of type PreCommitTask which can be just common interface.
Also this maybeRegister method is relative expensive.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thinking more about it an alternative would be if the specific PreCommit plugins are just responsible to wire things against the precommit task. That way you could skip the specific common task type. so these plugins would look always like

...
apply(PreCommitPlugin)
// register tasks I want to wire
tasks.named("precommit").configure { dependsOn 'specificTask; }
...

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it would be better to not extend this Plugin in other PrecommitPlugins but use composition here

Using inheritance allows us ensure the correct wirings happen. With composition, we can forget to hook up the new task to precommit, but with inheritance we enforce this because the class and createTask methods are abstract. Additionally, it wouldn't make sense to have precommit alone, it only makes sense in the context of having a concrete task like forbiddenapis.

The other specific precommit plugins would only need to ensure that the tasks they create are of type PreCommitTask

We can't guarantee this since some tasks are external, like forbidden apis or checkstyle.

Copy link
Contributor

@breskeby breskeby May 19, 2020

Choose a reason for hiding this comment

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

I see. I would still split out the generation of the precommit task to a small (internal) plugin (e.g. PrecommitBase Plugin. By internal I mean we would not need to provide a public id for the plugin or even make it package protected. And here we would just apply this base plugin. This way we

a) ensure this task registration is done in a gradle idiomatic way
b) ensure its only applied by the specific PreCommit Plugins.

this is a common pattern in gradle where a plugin just provides a lifecycle task and other plugins hook into this lifecycle.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think a separate plugin that creates the precommit task might be the way to go as well. Primary reason being that maybeRegister does exception-based flow control, which is incredibly expensive and basically negates all benefits of lazy tasks. In fact, I'd recommend we completely remove that method so folks don't use it. We are throwing hundreds of exceptions here during configuration time. Filling all those stack frames has a big penalty.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍 small general thought on findByName. findByName often is an indicator of weak modelling that can be improved. I think in the build there's a lot of logic that is based on tasks that are around which should be more about what type of project (which plugins are applied) are we dealing with.

Copy link
Contributor

Choose a reason for hiding this comment

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

findByName often is an indicator of weak modelling that can be improved
That's definitely true. If you have to check if a task exists that indicates a code smell.

Copy link
Contributor

Choose a reason for hiding this comment

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

After chatting with Ryan I think I'm fine with plugin class extension. I'm less concerned about extending plugins when the superclass is abstract, that at least indicates this is purposeful. Extending non-abstract plugins is a no-no, and composition should be used instead as you say.

We can then have the abstract plugin apply a plugin which creates the precommit task that way Gradle handles idempotency for us rather than using maybeRegister.

Copy link
Contributor

Choose a reason for hiding this comment

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

We can then have the abstract plugin apply a plugin which creates the precommit task that way Gradle handles idempotency for us rather than using maybeRegister.

👍

Copy link
Member Author

Choose a reason for hiding this comment

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

I pushed b5dff57 which no longer uses maybeCreate. Instead we have an inner plugin that creates the task, but we still use inheritance to ensure we don't forget to add a task to it.

@rjernst
Copy link
Member Author

rjernst commented May 19, 2020

I wonder if we should rethink the term precommit

I often saw the term sanityCheck

You are correct that precommit is a sanity check. The terminology comes from the Lucene build (we have quite a few Lucene developers who work on both projects). For that reason, I don't think we should change the name.

});
precommit.configure(t -> t.dependsOn(task));

project.getPluginManager().withPlugin("java", p -> {
Copy link
Contributor

Choose a reason for hiding this comment

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

In my opinion we should extract that into a JavaPreCommit plugin. this also ensure this code is not executed more than once per project.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's not doing anything extra, there is no java precommit task. This is only ensuring when we have java projects with precommit, we wire up the precommit task in the desired order. I can move it so it is only applied once.

@breskeby
Copy link
Contributor

I wonder if we should rethink the term precommit

I often saw the term sanityCheck

You are correct that precommit is a sanity check. The terminology comes from the Lucene build (we have quite a few Lucene developers who work on both projects). For that reason, I don't think we should change the name.

I wonder if we should rethink the term precommit

I often saw the term sanityCheck

You are correct that precommit is a sanity check. The terminology comes from the Lucene build (we have quite a few Lucene developers who work on both projects). For that reason, I don't think we should change the name.

got it.

Copy link
Contributor

@breskeby breskeby left a comment

Choose a reason for hiding this comment

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

lgtm 👍

@rjernst rjernst merged commit c98d548 into elastic:master May 20, 2020
@rjernst rjernst deleted the buildsplit7 branch May 20, 2020 20:12
rjernst added a commit to rjernst/elasticsearch that referenced this pull request May 20, 2020
Each precommit task is currently registered inside the shared
PrecommitTasks class. Having a single class with all precommit tasks
makes individualizing which precommit tasks are needed based on type of
project difficult, where we often just disable somet tasks eg for all qa
projects. This commit creates plugins for each precommit task, and moves
the configuration of the task into each plugin. PrecommitTasks remains
for now, and just delegates to each plugin, but will be removed in a
future change.
rjernst added a commit that referenced this pull request May 20, 2020
Each precommit task is currently registered inside the shared
PrecommitTasks class. Having a single class with all precommit tasks
makes individualizing which precommit tasks are needed based on type of
project difficult, where we often just disable somet tasks eg for all qa
projects. This commit creates plugins for each precommit task, and moves
the configuration of the task into each plugin. PrecommitTasks remains
for now, and just delegates to each plugin, but will be removed in a
future change.
rjernst added a commit that referenced this pull request May 20, 2020
Each precommit task is currently registered inside the shared
PrecommitTasks class. Having a single class with all precommit tasks
makes individualizing which precommit tasks are needed based on type of
project difficult, where we often just disable somet tasks eg for all qa
projects. This commit creates plugins for each precommit task, and moves
the configuration of the task into each plugin. PrecommitTasks remains
for now, and just delegates to each plugin, but will be removed in a
future change.
rjernst added a commit that referenced this pull request May 21, 2020
Each precommit task is currently registered inside the shared
PrecommitTasks class. Having a single class with all precommit tasks
makes individualizing which precommit tasks are needed based on type of
project difficult, where we often just disable somet tasks eg for all qa
projects. This commit creates plugins for each precommit task, and moves
the configuration of the task into each plugin. PrecommitTasks remains
for now, and just delegates to each plugin, but will be removed in a
future change.
@mark-vieira mark-vieira added Team:Delivery Meta label for Delivery team and removed Team:Core/Infra Meta label for core/infra team labels Nov 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants