-
Notifications
You must be signed in to change notification settings - Fork 24.9k
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
RFC: Test that example plugins build stand-alone #32235
Conversation
The initial goal was to write a test to make sure that build-tools can be used by plugin authors outside of our build. Example projects seemed like a good fit rather than writing dummy ones just for the test. - Add an integration test based on testKit to build the example plugins like stand alone projects - the tests injects the snapshots repo right now - an alternative would be to inject the last release version to cause dependency resolution against that. It wouldn't be 100% realistic as we would build using old dependencies and current build-tools which never happens in practice, but it would result in fewer moving parts. - the snapshots does cover more ground at the cost of some confusion as these are delayed from the current build, so any new issues will introduced will surface in the next build only. - there are also some changes for making it easier to copy these examples, but it won't quite work yet, e.x. applying the plugin only works because of testKit. Applying the project like this won't work. It might work if we add a version number and publish it to the Gradle plugin portal. - testKit can have the gradle version configured, so it would be easy to add similar tests for different Gradle versions. - The tests are failing due to 2 reasons: - elasticsearch-nio is not published. I am looking to fix this. - `painless-whitelist` references `project(':modules:lang-painless')` so this isn't really an example that will work stand-alone. Not sure what we should do about this one? Not test it or publish the plugin jar ?
Pinging @elastic/es-core-infra |
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 like the idea of adding something to the build to test the build. I'm worried that using stale artifacts will cause spurious failures when we update the API.
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.
Thanks for taking this on! It is a sorely needed part of our testing to be complete. I am apprehensive about this approach, though, for a couple reasons:
- We've spent a lot of time moving away from depending on snapshots. If I understand this correctly, the example plugins would now be using a different version of build-tools (the latest published), and that would also depend on us publishing to gradle's plugin portal (which we should do, but needs to be done separately and automated with the rest of the release process).
- Currently, using our build plugin requires adding build-tools as a build dep in buildscript, and a specific version is what we recommend, since plugins must be built against a specific version of elasticsearch. The examples here have no version specified, so users copying them would just always pickup the latest we published to gradle's plugin portal. However, I don't think we want to have the version copy/pasted in each file since that would make version bumping much more error prone.
- The testing here is lower level than I think we want (test kit) for checking this very high level integration (can a basic project using our build plugin work).
I've thought about this in the past and have 2 other possible ideas.
- Have a test which invokes a new gradle invocation, specifying each project independently, but first copying the build file into a temporary location where it can be prefixed with the appropriate buildscript block to include the locally built buildSrc.
- Have a test which has a custom settings.gradle (again, invoked by a gradle build task) which uses pluginManagement to point to our local build of build-tools, so that the plugin block resolves completely locally. We would need this in both our normal settings.gradle and the one used by the test.
In either of these cases, I think we should discuss with the @esdocs team about a new top level area for plugin development docs. We should "publish" all of our example plugins (in addition to a lot of other basic how to type stuff for plugins). Part of that publishing can inject the appropriate beginning part of the build file whether it uses buildscript or plugin blocks. This way either case can have the exact version of elasticsearch the docs are built for. Obviously this is a broader task outside the scope of simply ensuring build-tools work at all with standalone plugins, but I wanted to point it out as a desirable future state that we should consider in how this all works.
@@ -56,17 +56,38 @@ class PluginPropertiesExtension { | |||
|
|||
/** A license file that should be included in the built plugin zip. */ | |||
@Input |
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 don't think this can be @input if it is private? It needs the default visibility to allow groovy/gradle to wrap in such a way that changes can be tracked.
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.
good catch, thanks!
The annotation needs to be on the getter, then we can keep this private to make sure it goes trough the setter.
runAndRemove("rescore"); | ||
} | ||
|
||
public void testRestHandler() 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.
I don't like these being hardcoded. We will definitely forget to add new examples here.
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 reason they are hard coded is that we still run all even if one fails, without rewriting this logic in unit + muting tests is easier too.
We will not forget to add new ones as in this case the test will fail.
Look at @AfterClass
i'm not happy about how it changes that static state of the test class, but since it's a test I think it's ok. Essentially we pop the plugin from the list at the start of each test and assert that each plugin has one.
I initially had a loop and changed it to this as soon as I realized we might wan to take decisions based on individual plugins.
@nik9000 @rjernst thank you for your helpful though! I think I might have slightly misled you and need to do some clarification.
That is not correct. The test does not depend on any repo for As I was writing this I just realized:
My understanding is that a copy paste would result in an error since the version is not specified. The new syntax can load plugins from:
The
I'm not sure what you mean here. AFAIK testKit uses the Gradle Tooling API, the same used by Idea and build ship to get Gradle configurations and run builds. The only problem I have with testKit is that it passes in class and resource directories of the plugin under tast, rather than the Jar. I imagine this was done since it would be awkward in Gradle terms to start having a dependency between test and jar, but we can always add that dependency and patch the generated meta-info file, I tested that and it works, but wanted to limit the size of this PR. It's not that important, as relying on something like ++ on finding a home for docs and documenting it. |
I would like feedback on this as well
How would a user go about copying this ? Given that AFAIK |
This is leftover from a first iteration of painless whitelists and can actually be updated to use the spi jar that we do publish for painless. |
elastic/release-manager#401 fixes elasticsearch-nio, and I replaced the project reference with spi.
|
Will publish everything that has publishing configured to a local repo
@nik9000 @rjernst This is ready for a final review, in a less controversial form. I solved the problem with the dependencies by configuring a maven repository backed by a local directory for every publication we have, and then pass that to the tests to use as a repo. The tests now essentially simulate a repo of what was just built and use it to build the plugins stand alone. Other changes in the PR are to make that pass. The problem of configuring a publishing in the build that will not actually be published in release manager, e.x. the problem we had with Ideally we should only have publications for what we actually publish, and make sure we actually publish everything we have a publication for. I think the RM could check this. |
public TemporaryFolder tmpDir = new TemporaryFolder(); | ||
|
||
@BeforeClass | ||
public static void assertProjectsExist() { |
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.
Redo this into a loop.
This generally looks good, but I think it is important to not require new example plugins remember to add a test. Instead, the test should iterate over all example plugins. |
I realized that this is similar to how we run yaml tests, so I found the randomized testing fw has |
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.
Thanks for the update, I have few more comments
build.gradle
Outdated
repositories { | ||
maven { | ||
name = 'localTest' | ||
url = "$rootProject.buildDir/local-test-repo" |
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 ${rootProject.buildDir}
as it is more clear where the substitution ends.
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 still seems outstanding?
build.gradle
Outdated
// Make nebula and shadow play nice together, Gradle doesn't like it how one jar task replaces the output of another | ||
// if both are part of published artifacts | ||
project.afterEvaluate { | ||
if (plugins.hasPlugin(MavenPublishPlugin) && plugins.hasPlugin(ShadowPlugin)) { |
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 this something that should be in BuildPlugin?
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 don't have a strong preference. I'm thinking build plugin will be implemented in Java and perhaps the bulk of it split into smaller focused classes. In this respect small scripts and glue could live and would be easier to write in the groovy script.
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.
It seems wrong to me to have the shadow plugin and publishing be something we support via BuildPlugin, yet require additional hacks within our build files.
systemProperty ( | ||
'test.build-tools.plugin.examples', | ||
files( | ||
project(':example-plugins').subprojects.collect { it.projectDir } |
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 wonder I this test would make more sense inside plugins/examples
, so one could just run check
under there and be confident the examples are setup correctly?
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 don't think one is better than the other. It's an integration between the too, and right now chances are greater that build-tools will break the test as the plugins barely change. I taught about it too because it's odd to a new example ad have a distant projects tests break. We could always move them around or create a project in qa
- which I think would be in-line with how we handle this in general.
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 don't see this as an integration between the two. The examples are on their own. They use the build-tools, like any other project within the repo. This test is about ensuring those projects build files are correct. Ensuring build-tools is not itself broken is a place other tests here, IMO. Actually, I think it would be even nicer if each example plugin had an additional integration test task in place to check that specific plugin. This would make reproducing failures a lot easier (since it is a task on the project that fails).
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 fine with a task on the example plugins, but not entirely convinced it's worth the effort now . I started writing these tests to make sure build-tools can run for other builds too, something that the example plugins helped with. We build these during the regular build so making sure build script and all is correct is already done there to some extent. I propose we do this in a subsequent PR after seeing where this approach takes us, so we can get some tests running and feedback before we invest more effort into it.
" maven {\n" + | ||
" url \"" + getLocalTestRepoPath() + "\"\n" + | ||
" }\n" + | ||
" maven {\n" + |
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 we conditionally add this only if the build is using a lucene snapshot?
} | ||
|
||
private String getLuceneSnapshotRevision() { | ||
return System.getProperty("test.luceene-snapshot-revision", "not-a-snapshot"); |
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: luceene -> lucene
@@ -17,15 +17,21 @@ | |||
* under the License. | |||
*/ | |||
|
|||
apply plugin: 'elasticsearch.esplugin' | |||
plugins { | |||
id 'elasticsearch.esplugin' |
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 still don't like having this using the plugins dsl until we actually have build-tools published to the gradle plugin portal. While these examples currently are missing the buildtools section to make apply work outside the build, if they are copied with the plugins block they will never work, and the purpose of these is to make the examples copyable.
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 not entirely happy about it either, but it handles the injection of the plugin that was just built, a lot of boilerplate that this DSL and testKit helps us avoid. That being said, I think with what we have now, we could inject the local repo into the build script classpath and easily avoid that boilerplate. I will take a look.
} | ||
|
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.
nit: extra newlines
@rjernst now using the old syntax to apply plugin. |
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.
Thanks @atorok. Your proposal to address my concerns in a followup is fine with me.
Add tests for build-tools to make sure example plugins build stand-alone using it. This will catch issues such as referencing files from the buildSrc directly, breaking external uses of build-tools.
Add tests for build-tools to make sure example plugins build stand-alone using it. This will catch issues such as referencing files from the buildSrc directly, breaking external uses of build-tools.
* 6.x: (42 commits) [DOCS] Splits the users API documentation into multiple pages (#32825) [DOCS] Splits the token APIs into separate pages (#32865) [DOCS] Creates redirects for role management APIs page Bypassing failing test PainlessDomainSplitIT#testHRDSplit (#32966) TEST: Mute testRetentionPolicyChangeDuringRecovery [DOCS] Fixes more broken links to role management APIs [Docs] Tweaks and fixes to rollup docs [DOCS] Fixes links to role management APIs [ML][TEST] Fix BasicRenormalizationIT after adding multibucket feature [DOCS] Splits the roles API documentation into multiple pages (#32794) [TEST] Run pre 6.4 nodes in non-FIPS JVMs (#32901) Remove assertion in testDocStats on deletedDocs counter (#32914) [ML] fix updating opened jobs scheduled events (#31651) (#32881) Enable FIPS140LicenseBootstrapCheck (#32903) HLRC: Move ML request converters into their own class (#32906) [DOCS] Update getting-started.asciidoc (#29518) Fix allowed value for HighlighterBuilder encoder in javadocs (#32780) [DOCS] Add "remove a tag" script logic as an example (#32556) RFC: Test that example plugins build stand-alone (#32235) Security: remove put privilege API (#32879) ...
The initial goal was to write a test to make sure that build-tools can
be used by plugin authors outside of our build. Example projects seemed
like a good fit rather than writing dummy ones just for the test.
like stand alone projects
dependency resolution against that. It wouldn't be 100% realistic
as we would build using old dependencies and current build-tools
which never happens in practice, but it would result in fewer
moving parts.
as these are delayed from the current build, so any new issues will
introduced will surface in the next build only.
examples, but it won't quite work yet, e.x. applying the plugin
only works because of testKit. Applying the project like this won't work.
It might work if we add a version number and publish it to the
Gradle plugin portal.
add similar tests for different Gradle versions.
painless-whitelist
referencesproject(':modules:lang-painless')
so this isn't really an example that will work stand-alone.
Not sure what we should do about this one? Not test it or publish
the plugin jar ?
@nik9000 @rjernst @jasontedor Do you think this something we should pursue ? What should we do about
painless-whitelist
? Will the delayed failures due to the snapshots repo be too problematic ?