diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 0000000000..21e99e9ceb
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,14 @@
+# Commits listed here are skipped by `git blame` so that mechanical, whole-tree
+# reformats do not obscure the author who actually wrote each line.
+#
+# GitHub honors this file automatically in the web blame view. For `git blame`
+# on the command line, opt in once per clone:
+#
+# git config blame.ignoreRevsFile .git-blame-ignore-revs
+#
+# When adding a new entry, include a one-line comment above the SHA explaining
+# what the commit did and why it should be skipped. Only mechanical reformats
+# belong here -- never use this to hide substantive changes.
+
+# Apply Palantir Java Format to entire codebase (#1761)
+e80374ba8559a0b124e868d906de9fb59482752c
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index e336d3c9fa..4f1a4eb7f6 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -71,6 +71,23 @@ jobs:
with:
name: test-results-external-apis
path: build/reports/tests
+ formatCheck:
+ runs-on: ubuntu-latest
+ name: Java Format Check
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0 # full history + tags so palantir/git-version sees the latest release tag
+ - name: Set up java 17
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'adopt'
+ cache: gradle
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+ - name: Verify formatting
+ run: ./gradlew spotlessCheck
spotBugs:
runs-on: ubuntu-latest
name: SpotBugs
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 40ec5a95ef..e84d014a2e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,5 +1,38 @@
# Contributing to HTSJDK
+## Code Style
+
+HTSJDK uses [Palantir Java Format](https://github.com/palantir/palantir-java-format)
+(applied via the [Spotless](https://github.com/diffplug/spotless) Gradle plugin)
+to enforce a single, mechanical code style across the codebase. There are no
+formatting knobs to configure -- the formatter is the style guide.
+
+Formatting is applied automatically as part of `compileJava`: every build
+runs `spotlessJavaApply`, which rewrites any unformatted source in place
+before compiling. In normal use you shouldn't need to invoke the formatter
+yourself -- just build, and your code is formatted. If you want to format
+without compiling, run:
+
+```bash
+./gradlew spotlessApply
+```
+
+CI runs `./gradlew spotlessCheck` (verify-only, no mutation) so a PR with
+unformatted code still fails CI -- the local auto-format is a convenience,
+not the enforcement boundary.
+
+### Git blame and the bulk-format commit
+
+The codebase was reformatted in a single mechanical commit. To keep `git blame`
+useful (so you see the author who actually wrote each line, not the reformat
+commit), the repository ships a `.git-blame-ignore-revs` file. GitHub honors
+it automatically in the web UI; for `git blame` on the command line, opt in
+once per clone:
+
+```bash
+git config blame.ignoreRevsFile .git-blame-ignore-revs
+```
+
## Building
HTSJDK uses Gradle (via the Gradle wrapper). To build:
diff --git a/build.gradle b/build.gradle
index f83371d7bf..799bc0d50c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,6 +13,14 @@ plugins {
id 'com.gradleup.shadow' version '9.4.1'
id 'com.github.spotbugs' version "6.4.8"
id 'com.gradleup.nmcp' version '1.4.4'
+ id 'com.diffplug.spotless' version '8.4.0'
+}
+
+spotless {
+ java {
+ target 'src/**/*.java'
+ palantirJavaFormat()
+ }
}
repositories {
@@ -135,6 +143,12 @@ defaultTasks 'jar'
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
+ // Auto-format source as part of every compile. This rewrites unformatted
+ // files in place rather than failing -- contributors don't have to remember
+ // to run `./gradlew spotlessApply` themselves. spotlessJavaApply is fast
+ // (sub-second warm) thanks to Gradle's up-to-date checking. CI separately
+ // runs `spotlessCheck` (verify-only) so unformatted code can't slip past.
+ dependsOn 'spotlessJavaApply'
}
tasks.withType(Javadoc).configureEach {
diff --git a/java-style-eclipse.xml b/java-style-eclipse.xml
deleted file mode 100644
index 4f9d8d6b9c..0000000000
--- a/java-style-eclipse.xml
+++ /dev/null
@@ -1,337 +0,0 @@
-
-
@@ -26,7 +27,7 @@ public class HtsCodecRegistry {
* Create a registry. Protected to prevent use outside of the registry package. To create
* a private registry from outside the registry package, use {@link #createPrivateRegistry}.
*/
- protected HtsCodecRegistry() { }
+ protected HtsCodecRegistry() {}
/**
* Add a codec to the registry. If a codec that supports the same (format, version) (determined
@@ -66,15 +67,21 @@ protected HtsCodecRegistry() { }
*
* @return a mutable registry instance for private use
*/
- public synchronized static HtsCodecRegistry createPrivateRegistry() {
+ public static synchronized HtsCodecRegistry createPrivateRegistry() {
final HtsCodecRegistry privateRegistry = new HtsCodecRegistry();
// propagate the codecs from the sourceRegistry to the new registry
- HtsDefaultRegistry.htsDefaultCodecRegistry.getHaploidReferenceResolver().getCodecs()
+ HtsDefaultRegistry.htsDefaultCodecRegistry
+ .getHaploidReferenceResolver()
+ .getCodecs()
+ .forEach(c -> privateRegistry.registerCodec(c));
+ HtsDefaultRegistry.htsDefaultCodecRegistry
+ .getReadsResolver()
+ .getCodecs()
.forEach(c -> privateRegistry.registerCodec(c));
- HtsDefaultRegistry.htsDefaultCodecRegistry.getReadsResolver().getCodecs().
- forEach(c -> privateRegistry.registerCodec(c));
- HtsDefaultRegistry.htsDefaultCodecRegistry.getVariantsResolver().getCodecs()
+ HtsDefaultRegistry.htsDefaultCodecRegistry
+ .getVariantsResolver()
+ .getCodecs()
.forEach(c -> privateRegistry.registerCodec(c));
return privateRegistry;
}
@@ -84,21 +91,25 @@ public synchronized static HtsCodecRegistry createPrivateRegistry() {
*
* @return the {@link HaploidReferenceResolver} for this registry
*/
- public synchronized HaploidReferenceResolver getHaploidReferenceResolver() { return htsHaploidReferenceResolver; }
+ public synchronized HaploidReferenceResolver getHaploidReferenceResolver() {
+ return htsHaploidReferenceResolver;
+ }
/**
* Get the {@link ReadsResolver} for this registry.
*
* @return the {@link ReadsResolver} for this registry
*/
- public synchronized ReadsResolver getReadsResolver() { return htsReadsResolver; }
+ public synchronized ReadsResolver getReadsResolver() {
+ return htsReadsResolver;
+ }
/**
* Get the {@link VariantsResolver} for this registry.
*
* @return the {@link VariantsResolver} for this registry
*/
- public synchronized VariantsResolver getVariantsResolver() { return htsVariantsResolver; }
-
+ public synchronized VariantsResolver getVariantsResolver() {
+ return htsVariantsResolver;
+ }
}
-
diff --git a/src/main/java/htsjdk/beta/plugin/registry/HtsCodecResolver.java b/src/main/java/htsjdk/beta/plugin/registry/HtsCodecResolver.java
index dbfc7d7ed2..cd83db6b4e 100644
--- a/src/main/java/htsjdk/beta/plugin/registry/HtsCodecResolver.java
+++ b/src/main/java/htsjdk/beta/plugin/registry/HtsCodecResolver.java
@@ -1,18 +1,17 @@
package htsjdk.beta.plugin.registry;
+import htsjdk.annotations.InternalAPI;
+import htsjdk.beta.exception.HtsjdkException;
import htsjdk.beta.exception.HtsjdkIOException;
-import htsjdk.beta.plugin.HtsCodec;
-import htsjdk.beta.plugin.HtsVersion;
+import htsjdk.beta.exception.HtsjdkPluginException;
import htsjdk.beta.io.bundle.Bundle;
import htsjdk.beta.io.bundle.BundleResource;
import htsjdk.beta.io.bundle.SignatureStream;
-import htsjdk.beta.exception.HtsjdkException;
-import htsjdk.beta.exception.HtsjdkPluginException;
+import htsjdk.beta.plugin.HtsCodec;
+import htsjdk.beta.plugin.HtsVersion;
import htsjdk.io.IOPath;
import htsjdk.samtools.util.Log;
-import htsjdk.annotations.InternalAPI;
import htsjdk.utils.ValidationUtils;
-
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
@@ -37,8 +36,8 @@
public class HtsCodecResolver