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

Add plugin support for Bazel #76

Open
jbduncan opened this issue Jan 20, 2017 · 14 comments
Open

Add plugin support for Bazel #76

jbduncan opened this issue Jan 20, 2017 · 14 comments

Comments

@jbduncan
Copy link
Member

jbduncan commented Jan 20, 2017

Bazel is something which has interested me for a while now, so writing a Spotless plugin for it may prove to be a good way to get my feet wet with it. However I'm limited for time with my studies and I suspect I won't be able to work on something this big until late May 2017 or later.

Here's what I currently understand about Bazel with regards to plugin-writing:

  1. Bazel uses a subset of Python called Skylark for writing extensions (Bazel's terminology for plugins AFAICT). So it may very well be that Spotless would need to be ported to Skylark first, which isn't ideal.
  2. There seem to be ways of integrating shell scripts and binaries as extensions into Bazel. I'm hoping that we can use one of these options or some another option to call spotless-lib (or a Java binary wrapper around it) without porting it to Skylark.
@jbduncan
Copy link
Member Author

Note to self: AFAICT, Bazel only has one build command, so we may have to choose one of spotlessApply and spotlessCheck to use as the plugged-in sub-command, or give up trying to integrate Spotless into Bazel directly and provide a command-line wrapper similarly to google-java-format instead (to allow Bazel users to manually integrate Spotless in whatever way they see fit).

@jbduncan
Copy link
Member Author

AFAICT, Bazel only has one build command, so we may have to choose one of spotlessApply and spotlessCheck to use as the plugged-in sub-command...

Ah, just to correct myself, I now understand that Bazel has a build command which can build any so-called "target" defined in a BUILD file (equivalent to Gradle's build.gradle file), so it may be possible to write one target for spotlessCheck and another for spotlessApply...

@jbduncan
Copy link
Member Author

@nedtwigg I've realised that I've not had the time and interest to pursue this further as of late. How would you like me to deal with this issue for now?

@nedtwigg
Copy link
Member

Just upload anything you think might be useful to somebody else who might wanna do this 👍

@jbduncan
Copy link
Member Author

Note for whoever wants to take this on: When naming the Bazel plugin, the Bazel developers recommend following these guidelines for naming it.

@jbduncan
Copy link
Member Author

Another note for whoever wants to take this on: IIUC, Spotless would need a command-line interface first, such that it could be run from the terminal without needing Gradle or Maven as an intermediary. Only then could Spotless be integrated as a Bazel "plugin" ("rule" being the correct term IIUC).

@jbduncan
Copy link
Member Author

...or, maybe I'm mistaken about needing a command-line interface! For all I know, Bazel's extension language Starlark could be powerful enough to allow Spotless to be ported. But further research would be needed.

@nedtwigg
Copy link
Member

@t-rad679
Copy link
Contributor

A colleague and I have been thinking about this a lot, and the cleanest way we've found is to start with a binary wrapper (as Jonathan suggested early on in this thread) that takes a config that specifies the same stuff you would in a build.gradle, use a custom Bazel rule to generate the config from attributes passed from the target, then write another Bazel rule calling the executable as an action. The config generation is a bit wonky, but this is still more or less in line with how Bazel was intended to work. We unfortunately did not run across any functionality in Starlark that allows interoperation between it and Java libraries in its extensions. Someone please let me know if they find out I missed something.

Seems to me like implementing said binary wrapper would basically amount to building a command line application, so it seems silly not to expose it as such for any users who want that (even if it's not really a standard use case). Would you guys accept a well written and tested implementation of a command line application for Spotless? It might be a while before I have the time, but we'd be willing to work on such a thing. Let me know and I'll open a ticket for it. Then I'd also be willing to put in some work on this ticket after that is complete.

@nedtwigg
Copy link
Member

Would you guys accept a well written and tested implementation of a command line application for Spotless?

Definitely! Some minor points

  • if it requires no deps, can live in lib
  • if it requires a few deps, it can live in lib-extra
  • if it requires a lot of new deps, it should live in a new project called cli (or something)

A broader, structural point is the "current feature matrix" in the root readme, and especially this note about it:

Why are there empty squares? Many projects get harder to work on as they get bigger. Spotless is easier to work on than ever, and one of the reasons why is that we don't require contributors to "fill the matrix". If you want to add Bazel support, we'd happily accept the PR even if it only supports the one formatter you use. And if you want to add FooFormatter support, we'll happily accept the PR even if it only supports the one build system you use.

I am fine with adding a new column for "bazel", or a new column for "CLI", but it's even better if "bazel" piggybacks on "CLI" which somehow piggybacks on either gradle or maven. jbang is a clever project which (ab)uses gradle to smash java into single-file-scripts, might have useful lessons for a similar piggybacking.

Implications of a CLI column

If the CLI gets its own column (which is fine), there are a few questions which have obvious answers in the context of a build-system-plugin (see docs), which are not-at-all-obvious in the context of an independent CLI.

  • "does the CLI define just the formatter function (which steps to apply and how they are configured), or does it define both the formatter function and the files to be formatted". Either is fine, but it's an important distinction to make.
  • how does the CLI download artifacts from a central repository / how is that configured / how are they cached locally

I don't know much about Bazel, but I would imagine that it has some kind of convention / opinion on these two topics. If it does, then the spirit of YAGNI might recommend that this CLI should have a package com.diffplug.spotless.bazel and another package com.diffplug.spotless.cli. It might not be practical for a raw CLI to figure out the questions above without having some opinionated build system (e.g. bazel) to draw certain utilities from. In this approach, the CLI could only actually be run within a Bazel build, but there's the option that a future contributor could leverage the same CLI to add e.g. SCons, CMake or some other non-JVM build system.

@t-rad679
Copy link
Contributor

Thanks Ned! I've created a ticket for the CLI and I'm going to respond to your last comment there. I know there's some crossover between talking about CLI and Bazel there, but it seems mostly focused around how to design the CLI.

@shs96c
Copy link

shs96c commented Nov 16, 2022

This looks like the kind of thing that we'd hook into https://github.com/apple/apple_rules_lint and expose via https://github.com/bazel-contrib/rules_jvm . Doing so would allow a test target and a "fix" target to be exposed as part of the build.

Can Spotless be run on a subset of the tree? Bazel targets tend to focus on a "per package" level in Java projects, and we'd want to have the same level of granularity here.

@nedtwigg
Copy link
Member

Can Spotless be run on a subset of the tree?

spotless-lib lets you take a list of steps and put them together in a Formatter. Then you call PaddedCell.calculateDirtyState(formatter, File input) and it tells you if that file is clean or not, and if it's not if tells you what it should be.

Defining a source tree to run on, up-to-date-checking, how you define the steps, etc. is all a concern of the plugin. spotless-plugin-maven does it one way, spotless-plugin-gradle does it a totally different way. Presumably Bazel has its own way.

@jbduncan
Copy link
Member Author

jbduncan commented Mar 10, 2023

If google-java-format issue google/google-java-format#917 ever reaches a positive conclusion, it could make porting Spotless to Bazel easier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants