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

How to run google-java-format from Bazel? #917

Open
vorburger opened this issue Mar 10, 2023 · 8 comments
Open

How to run google-java-format from Bazel? #917

vorburger opened this issue Mar 10, 2023 · 8 comments

Comments

@vorburger
Copy link
Member

I would like to run google-java-format in an (open source) project which uses Bazel as build system.

I currently have it set up using https://github.com/dustinsand/pre-commit-jvm (with https://pre-commit.com) but it strikes me as "odd" having to install https://get-coursier.io and relying on dustinsand/pre-commit-jvm when it should be possible to "just" have a (Maven) dependency on this in Bazel and "run it" - I'm just not entirely sure HOW one would be run a Java based tool like this one from Bazel...

... I have briefly explored something like what this post on bazel-discuss may have been after, and started to write my own GoogleJavaFormatTest using this project's API, but it doesn't seem to be intended to used like that (UsageException is package local only, even though Main#format(String... args) throws UsageException) - and integrated this as a b test //... is perhaps that's the wrong way to go about this anyway?

How would one best run google-java-format from Bazel? You would want it "run whenever any *.java changed", and one would want it to fail the build if the formatting was wrong - but re-write (correct) the source files. Is this possible with Bazel? How does one even "run a main() method from a dependency" for something like this?

@cushon perhaps you have some wise guidance?

@cushon
Copy link
Collaborator

cushon commented Mar 10, 2023

Can you say more about what the desired workflow would be? Would you like to be able to bazel run //some/target and have that format the files? Or a test that would fail if the files weren't formatted, and maybe print a separate command you could run to format them? I don't think there's a good way to do the first thing, the second one should be do-able.

@vorburger
Copy link
Member Author

vorburger commented Mar 10, 2023

@cushon anything that works, really; if there is no good way to do via bazel run, then a bazel test approach SGTM!

After staring at Main.java a bit, I had actually started to write my own GoogleJavaFormatTest - but got a bit stuck, as one couldn't call its public static void main(String[] args) from such a test because it has a System.exit(result). So then I started to explore invoking public int format(String... args), but that's a PITA because it throws UsageException - which is not visible (that could perhaps be a neat thing to detect e.g. in error-prone, perhaps?).

Would you welcome a contrib (PR) proposing some (backwards compatible) minor refactoring to class Main to make this possible / easier?

I guess it's not even Bazel related, per se... such a test could "dog food" and even run within this project!

@cushon
Copy link
Collaborator

cushon commented Mar 10, 2023

If you want a main-like interface, I'd look at using the GoogleJavaFormatToolProvider. There's a unit test for it with a usage example.

@vorburger
Copy link
Member Author

I'd look at using the GoogleJavaFormatToolProvider

public class GoogleJavaFormatTest {
    @Test
    public void testGoogleJavaFormat() {
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out, UTF_8));
        PrintWriter err = new PrintWriter(new OutputStreamWriter(System.err, UTF_8));
        Assert.assertEquals(0, new GoogleJavaFormatToolProvider().run(out, err, "--help"));
    }
}

works! Now I just need to figure out to... hm, what? I would probably want some Blaze java_test rule to get "all of the project's **/.*.java file paths" as its input, to pass to my GoogleJavaFormatTest?

I can't pass an argument to a test. Set a system property? (Not sure if that could run into length limitations...) Probably best to somehow get a file with all Java classes to format written, possibly with a fixed name, and @ that as an argument to the GoogleJavaFormatToolProvider?

But how do you do that - glob for files and have Bazel write that into a file? And would that java_test have to be in a BUILD.bazel file at the root of the project, in order to be "allowed" to find/see ALL **/.*.java files?

I don't know how to do the Bazel part... 😭 Will read up and ask around - and welcome any pointers & tips!

@cushon
Copy link
Collaborator

cushon commented Mar 10, 2023

Note that you don't need to instantiate the class directory, you can also use the ToolProvider SPI:

For the Bazel part, tests can only see files if they're inputs in the build graph. I don't know a standard way to make all of the .java files in a project inputs. If you want to check all of the sources that are inputs to a particular java_binary there's a _deploy-src.jar artifact that rolls up the transitive sources, but that's just the inputs to that binary, not the entire project. Another approach would be to have a CI rule that tried to build everything, and used an aspect to check if sources were formatted.

@jbduncan
Copy link
Contributor

A proposed solution for porting Spotless to Bazel is to use the third-party https://github.com/apple/apple_rules_lint, so I wanted to let you both know if this possibility in case you hadn't considered it already. :)

@vorburger
Copy link
Member Author

FYI I personally won't be actively pursuing this further, because I've settled on using https://github.com/macisamuele/language-formatters-pre-commit-hooks/ instead of a Bazel integrated approach, for my current project, for now. (I suspect it is more "incremental" than a Bazel-based solution could be; as https://pre-commit.com uses git to check only changed files.) But I'm leaving this issue open just in case this analysis/discussion is ever of any use to others in the future.

@vorburger
Copy link
Member Author

#216 (for bazel-contrib/rules_jvm#23) seems to be related to this...

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

No branches or pull requests

3 participants