Skip to content
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

Replace Gradle init scripts with a proper Gradle plugin #565

Merged
merged 38 commits into from
May 10, 2023
Merged

Conversation

keynmol
Copy link
Contributor

@keynmol keynmol commented Apr 25, 2023

This PR replicates the functionality of the init script injection with a proper Gradle plugin + a much smaller init script.

Benefits:

  1. You can edit the plugin code in IDE - it's a normal SBT module
  2. Cleaner and doesn't rely as much on values injected as strings
  3. More flexible as it can be added to the builds as both an assembly jar (for auto-indexing) or a maven central dependency (in the future)
  4. Works for gradle 6, 7, and 8, toolchains included (tested on jdk 8, 11, 17)
  5. Most of the logic is done inside the plugin, not in combination of scip-java and init script

Additionally:

  • Run CI for Java 11
  • Run tests for 3 major gradle versions
  • Produce a meaningful message if we get an exception from javac
Old TODO list TODO: - [x] Restore kotlin multi-platform support - [x] Add dependency dump task - [x] Modify tests to run on various gradle versions - [x] Disable publishing of the gradle plugin for _now_ Currently it's written in Scala as it allows for much faster prototyping. With it not being published but rather injected via assembly, it doesn't matter what language it's written in.

Once we have this merged and tested in the wild, we can start the process of rewriting the plugin in Java (for maximum compatibility) and publish it - after that, the docs can be modified and all manual steps removed.

Old description from where I was just a young pup helplessly thrashing about TODO: - [x] Kotlin support - [x] Rewrite init script > One main limitation of init scripts is that they cannot access classes in the buildSrc project (see [Using buildSrc to extract imperative logic](https://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:build_sources) for details of this feature). ![](https://media.giphy.com/media/vyTnNTrs3wqQ0UIvwE/giphy.gif)

Current plan:

Test plan

  • Extra tests for Gradle versions: 6.7 (introduced toolchains), 7.5.1 (latest in 7.x lineage), 8.1.1 (latest)
  • Confirm all old tests are passing

Sorry, something went wrong.

@keynmol keynmol marked this pull request as ready for review May 5, 2023 09:43
keynmol added 9 commits May 5, 2023 10:46
Our approach can fail if the build modifies the compile classpath
as part of the build definition:

> Cannot change dependencies of dependency configuration ':compileOnly' after it has been included in dependency resolution.

In this case we go the agent route
@keynmol keynmol changed the title WIP: Injectable gradle plugin Replace Gradle init scripts with a proper Gradle plugin May 5, 2023
Comment on lines 39 to 41
val javacDep = javacPluginJar
.map[Object](jar => project.files(jar))
.getOrElse(s"com.sourcegraph:semanticdb-javac:${javacPluginVersion}")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We fallback to javac plugin published to maven if there is no jar specified

Copy link
Member

Choose a reason for hiding this comment

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

Could have been a decent inline comment instead of PR comment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

j'agree

System
.err
.println(
s"Failed to add compiler plugin to javac, will go through the agent route: ${exc.getMessage()}"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

At the time when the plugin is loaded, compileOnly configuration might already be resolved, if triggered by something in the build: https://sourcegraph.com/github.com/awslabs/smithy-language-server/-/blob/build.gradle?L212

Comment on lines +75 to +82
println(
task
.asInstanceOf[{
def getToolChain(): Any
}
]
.getToolChain()
)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TODO: see what we can do about this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Given Gradle's compatibility matrix (only 7.3+ supports Java 17) this branch doesn't need anything.

I have a spearate PR coming that will clean this up among other things

Comment on lines +87 to +91
val host = System
.getProperty("java.version")
.split("\\.")
.headOption
.map(_.toInt)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

only at play where there is no toolchain provided

@olafurpg olafurpg self-requested a review May 9, 2023 06:31
Copy link
Member

@olafurpg olafurpg left a comment

Choose a reason for hiding this comment

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

This looks really really good 👏🏻 Nice work @keynmol

I love the plugin approach, it's a much cleaner solution than the unmaintainable init script. I can imagine us doing a lot more with Gradle using this plugin approach.

No blocking comments, just two nitpick suggestions to add type annotations. I'm fine with deleting the init script and moving into this bright new future 🌞

s"""
| initscript {
| dependencies{
| classpath(files("${gradlePluginPath}"))
Copy link
Member

Choose a reason for hiding this comment

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

TIL very cool 👍🏻

| project.extra["javacPluginJar"] = "$pluginpath"
| project.extra["dependenciesOut"] = "$dependenciesPath"
| project.extra["javacAgentPath"] = "$agentpath"
| apply<SemanticdbGradlePlugin>()
Copy link
Member

Choose a reason for hiding this comment

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

🥳 🥳 😍

Comment on lines 39 to 41
val javacDep = javacPluginJar
.map[Object](jar => project.files(jar))
.getOrElse(s"com.sourcegraph:semanticdb-javac:${javacPluginVersion}")
Copy link
Member

Choose a reason for hiding this comment

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

Could have been a decent inline comment instead of PR comment

s"-Xplugin:$semanticdbScalac",
s"-P:semanticdb:sourceroot:$sourceRoot",
s"-P:semanticdb:targetroot:$targetRoot",
s"-P:semanticdb:exclude:(src/play/twirl|src/play/routes|src/${System.currentTimeMillis()})", // Ignore autogenerated Playframework files
Copy link
Member

Choose a reason for hiding this comment

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

Nice 👍🏻

//
// Instead, we commit the sins of reflection for our limited
// needs.
val compilerArgs = task
Copy link
Member

Choose a reason for hiding this comment

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

this is fine

@keynmol keynmol merged commit 3ea8d94 into main May 10, 2023
@keynmol keynmol deleted the gradle-plugin branch May 10, 2023 09:33
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.

None yet

2 participants