-
Notifications
You must be signed in to change notification settings - Fork 458
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
Providing explicit support for Groovy source code (fixes #13) #94
Conversation
Supporting dedicated configuration for groovy source. The configuration allows access to formatter steps which have been introduced for Java, but which are also useable for Groovy code. Integrates Groovy-Eclipse based Groovy formatter step implementation. Allows coexistent configuration of Java and Groovy formatter steps.
Note that I also would like to align afterwards the Java related tests with the once for Groovy. But I think this should be done in a different PR. Maybe I should also split the current PR into changes for GrEclipseFormatterStep and changes for GroovyExtension. Let me know if you want a split. |
Very sorry this has languished so long. Conference last week swamped me, this week is catch up. I promise to review this this weekend (and hopefully merge :) |
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've had a very brief look through this PR. Nothing about the overall structure strikes out to me as needing attention, so I'm okay with how it looks so far.
What I'm concerned about though is that, AFAICT, there's no explicit documentation yet on what options one can use to configure a groovy.GrEclipseFormatterStep
. I understand that one can pass settings files to a step, but it's not clear to me what settings that a settings file can have and what the syntax is.
Has any documentation for this been written yet? I'd not, I think it would be worth creating a new PR with some basic instructions somewhere.
Oh, I just realised that there are instructions within this PR that seem to describe how to configure a I'll have a proper look at them later if/when I have the time. :) |
No worries. I had no time to continue with the work myself. |
…Set<String> has complicated serialization. Reused FileSignature.toSortedSet() for a more stable serialization. Also, using FileSignature.toSortedSet() without first calling asNonNulList() would be an error. So, might as well have toSortedSet() call that method itself as its first argument.
…ion its own invisible <a> tag for stable links.
This LGTM. I've published Currently waiting for inclusion into jcenter, then I can sync to mavencentral. Once we've got the artifact in there, we can change greclipse to not need any strange repositories, merge to master, and publish! |
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.
public static SerializableFileFilter skipFilesNamed(String name) { | ||
return new SerializableFileFilterImpl.SkipFilesNamed(name); | ||
/** Creates a FileFilter which will accept all files except files with the given name(s). */ | ||
public static SerializableFileFilter skipFilesNamed(String... names) { |
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 sure if this change is binary-compatible. Do we care about binary compatibility for public types in lib
, @nedtwigg?
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's definitely source-compatible, if not binary. Good enough while we've got zero users besides ourselves. Good catch though 👍
return false; | ||
} | ||
} | ||
return true; |
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 could be simplified to !Arrays.asList(namesToSkip).contains(pathname.getName())
, I believe.
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 could be, at the cost of a teensy-weensy allocation for every time we apply a step. Definitely premature optimization, but the long form is still easy to read.
plugin-gradle/README.md
Outdated
greclipseFormatFile 'greclipse.properties' | ||
} | ||
} | ||
``` |
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.
@nedtwigg, what do you think about touching up the comments in this code block as well?
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 for it. What comments do you want to touch up?
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 want to touch them up such that the code block looks like this:
spotless {
java {
licenseHeaderFile 'spotless.license.java'
googleJavaFormat() // use a specific formatter for Java files
}
groovy {
licenseHeaderFile 'spotless.license.java'
excludeJava // excludes all Java sources within the Groovy source dirs from formatting
// the Groovy Eclipse formatter extends the Java Eclipse formatter,
// so it formats Java files by default (unless `excludeJava` is used).
greclipseFormatFile 'greclipse.properties'
}
}
What do you think?
If you think this change is good, would you kindly push it for me? :)
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.
👍
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.
Thank you. 👍
|
||
public class GroovyExtension extends FormatExtension { | ||
public static final String NAME = "groovy"; | ||
public static final boolean EXCLUDE_JAVA_DEFAULT = false; |
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 believe NAME
could be made package-private and EXCLUDE_JAVA_DEFAULT
could be made private, if time allows.
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 :) I'll fix.
We're sooo close! Have an interesting problem. I tried using the groovy formatter in spotlessSelf.gradle as such: java {
...
eclipseFormatFile 'spotless.eclipseformat.xml'
}
groovy {
target 'build.gradle', 'spotlessSelf.gradle', 'settings.gradle'
greclipseFormatFile 'spotless.eclipseformat.xml'
} The problem is that GroovyExtension {
public void greclipseFormatFile(Object... greclipseFormatFiles) { ... }
public void greclipseFormatFile(String greclipseVersion, Object... greclipseFormatFiles) { ... }
} It's copied from the JavaExtension, which used to have these two methods: JavaExtension {
public void eclipseFormatFile(Object eclipseFormatFile) { ... }
public void eclipseFormatFile(String eclipseVersion, Object eclipseFormatFile) { ... }
} That was unambiguous. But now that we've turned If I could go back in time, I would make all of our versioned plugins work the way that the scala extension works. That pattern leaves much more room for future extensibility without bumping into these kinds of problems. But I don't want to break the Java DSL for our current users, and it makes sense for the Groovy and Java DSL to be similar. So I think our best approach is the workaround I'm about to upload. |
…and SpotlessExtension. This means that Spotless can now use greclipse to format its gradle files.
if (eclipseFormatFiles.length == 0) { | ||
eclipseFormatFiles = new Object[]{eclipseVersion}; | ||
eclipseVersion = EclipseFormatterStep.defaultVersion(); | ||
} | ||
Project project = getProject(); |
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 is naaasty. Here's a better way, maybe:
public class JavaExtension {
public EclipseCfg eclipse() {
return eclipse(EclipseFormatterStep.defaultVersion())
}
public EclipseCfg eclipse(String version) {
return new EclipseCfg(version);
}
// see https://github.com/diffplug/spotless/blob/a8ab1c1331376e57e63441417316139198c285de/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java#L38-L65 for implementation of EclipseCfg
public void eclipseFormatFile(Object fileArg) {
warning("Deprecated in favor of 'eclipse().configFile(fileArg)'")
eclipse().configFiles(fileArgs)
}
public void eclipseFormatFile(String version, Object fileArg) {
warning("Deprecated in favor of 'eclipse('" + version + "').configFile(fileArg)")
eclipse(version).configFiles(fileArgs)
}
}
The advantage of this approach is it gets all of our DSL on the Optional version argument -> config builder
pattern. The downside is it deprecates our main usecase for the sole purpose of accommodating the multiple-config-file-in-groovy usecase.
I'm inclined to avoid the question altogether by only allowing a single config file for both JavaExtension and GroovyExtension. It makes the docs simpler, and users can always concatenate groovy settings themselves. @fvgh how much will this limitation hurt GroovyExtension users?
I'm open to the deprecation path discussed above, but I don't have the time to do the proper testing, update the docs, etc.
@fvgh on an unrelated note, your ext-spotless-greclipse is in jcenter, but not mavencentral. I'm gonna wait til we're sure we've got it right to sync to mavencentral.
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.
How about replacing format file varargs...
public void greclipseFormatFile(String greclipseVersion, Object... greclipseFormatFiles) { ... }
...with two separate single-argument and iterable versions?
public void greclipseFormatFile(String greclipseVersion, Object greclipseFormatFile) { ... }
public void greclipseFormatFile(String greclipseVersion, Iterable<Object> greclipseFormatFiles) { ... }
...or a version where we require at least one format file?
public void greclipseFormatFile(String greclipseVersion, Object firstGreclipseFormatFile, Object... otherGreclipseFormatFiles) {
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.
greclipseFormatFile 'mycfg1.prop', 'mycfg2.prop'
. This will break all of your workarounds, I believe. It also breaks the workaround I've implemented in the previous commit.
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 can see how it would break my single-arg-and-iterable workaround, but not for my other one.
I'm not really familiar with Groovy, but if it were Java, I believe this would be syntactically correct if used with my latter workaround:
greclipseFormatFile('mycfg1.prop', 'mycfg2.prop');
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.
Unless, are we thinking of "breakage" in terms of "'mycfg1.prop'
will still be interpreted as the greclipseVersion
rather than the 1st greclipseFormatFile
"? (In which case, I'd agree.)
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.
My example above is from the README (loosely).
Pretty sure the travis failure is a bug in travis (it's building an old commit and reporting that it's building a new one). I've reported to Travis, hopefully will resolve with future commits. |
Sorry @nedtwigg and @jbduncan that you had to put in so much work on this PR.
To get a feeling how configuration shall look like: |
No apologies!! You've built a great feature that a lot of users want. The original sin here was me building a sloppy escape hatch for setting the version. In the bad old days, Spotless didn't have Provisioner, and all of its formatters were compile-time dependencies. That didn't scale as we added support for more languages, so we added Provisioner. A nice benefit of this abstraction is that now users can peg the version of their formatter implementation while still getting framework-level improvements, but it means that pre-Provisioner DSL either has no public mechanism for setting the version (FreshMark), or has a janky mechanism (Eclipse).
These both sound great. It's easy to make a nice warning message for helping legacy eclipseFormatFile users migrate.
Whatever's easier for you. I don't care if we close this PR and start fresh or whatever. This history is interesting but not critical.
I think so. |
The configuration allows access to formatter steps which have been introduced for Java, but which are also useable for Groovy code. Integrates Groovy-Eclipse based Groovy formatter step implementation. Allows coexistent configuration of Java and Groovy formatter steps.
@jbduncan Actually I did not a re-base. I just wanted to squash the commits. Ans since I was on it, I wanted to start at head of master since there were already conflicts reported. |
I am not sure, but it seems to me the Travis problem @nedtwigg was referring to is not a problem with Travis, but in my code. |
Yes confirmed. Just understood what PaddeCell does for me 😄 . Ok, still missing some basics about the project 😞 . Not sure why the problem (have not found the root cause yet) did not show up in the unit-tests. Should have been detected by GrEclipseFormatterStepTest. |
Sorry guys. Started to look for red herrings. The basics are sane. Must be some stupidity I inserted in the small refactoring I did for the last commit. Have to call it a day. Must postpone the PR until the weekend. |
@jbduncan I will omit the null-checks in this PR till your LibPreconditions.java is available. |
@fvgh Yep, it's alright with me. 👍 |
With the last change I introduced a proposal for the greclipsFormat ping-pong handling. The ping-pong is basically a ['C', 'A', 'B', 'A', 'B', ...] series. Hence it could not be solved by I did not fully research the ping-pong problem. It occurs even with the latest Groovy-Eclipse snapshot (Feb. 2017) in my Eclipse Neon.3. I used the formatter in the Eclipse GUI several times on the input Since I understood that @nedtwigg wanted too see a demonstration within this PR, I added a proposal in a separated commit. As you will observe, Groovy-Eclipse Formatter is far from the state the JDT formatter is in, but it is the best I know. |
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.
Hi @fvgh, I have requested some changes regarding your latest commit. Would you kindly look through them for me?
@@ -1,5 +1,5 @@ | |||
buildscript { | |||
repositories { maven { url 'https://plugins.gradle.org/m2/' } } | |||
repositories { maven { url 'https://plugins.gradle.org/m2/' }} |
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 should be formatted like the following (if possible):
repositories {
maven {
. . .
}
}
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.
That should work. The formatter should accept the format.
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.
Sorry, but the formatter always replaces nested closures by } } and then starting the ping-pong, unless I reformat it to }}.
Furthermore it cannot convinced to leave closures with one entry split over multiple lines.
@@ -20,7 +20,7 @@ javadoc { | |||
// use markdown in javadoc | |||
def makeLink = { url, text -> "<a href=\"${url}\" style=\"text-transform: none;\">${text}</a>" } | |||
def javadocInfo = '<h2>' + makeLink("https://github.com/${org}/${name}", "${group}:${project.ext.artifactId}:${ext.version}") + | |||
' by ' + makeLink('http://www.diffplug.com', 'DiffPlug') + '</h2>' | |||
' by ' + makeLink('http://www.diffplug.com', 'DiffPlug') + '</h2>' |
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.
Nice change! 👍
username = cred('nexus_user') | ||
password = cred('nexus_pass') | ||
} | ||
}} |
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 should be formatted like this (if possible):
repositories {
maven {
. . .
}
}
gradle/java-setup.gradle
Outdated
@@ -38,7 +34,8 @@ eclipseResourceFilters { | |||
apply plugin: 'findbugs' | |||
findbugs { | |||
toolVersion = VER_FINDBUGS | |||
sourceSets = [sourceSets.main] // don't check the test code | |||
sourceSets = [ | |||
sourceSets.main] // don't check the test code |
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.
You should manually reformat this line like this (if possible):
sourceSets = [
sourceSets.main // don't check the test code
]
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.
For array I have only a max length. For example with groovy.formatter.longListLength=1
, we can assure that all entries are in separate lines. Hence we can archive:
sourceSets = [
// don't check the test code
sourceSets.main
]
lib-extra/build.gradle
Outdated
@@ -22,6 +22,5 @@ dependencies { | |||
} | |||
|
|||
// we'll hold the core lib to a high standard | |||
findbugs { | |||
reportLevel = 'low' // low|medium|high (low = sensitive to even minor mistakes) | |||
findbugs { reportLevel = 'low' // low|medium|high (low = sensitive to even minor mistakes) | |||
} |
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's not clear to me why Greclipse formatted this section like this.
Can we prevent it with a setting?
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 think it is the comment, which is in the same line. The Groovy-Formatter seems only to accept this or method calls.
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.
Hmm, that's a shame.
Could we work around this problem with the following manual formatting?
findbugs { reportLevel = 'low' } // low|medium|high (low = sensitive to even minor mistakes)
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.
Yes, that works.
lib/build.gradle
Outdated
@@ -12,6 +12,5 @@ dependencies { | |||
} | |||
|
|||
// we'll hold the core lib to a high standard | |||
findbugs { | |||
reportLevel = 'low' // low|medium|high (low = sensitive to even minor mistakes) | |||
findbugs { reportLevel = 'low' // low|medium|high (low = sensitive to even minor mistakes) | |||
} |
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's not clear to me why Greclipse formatted this section like this.
Can we prevent it with a setting?
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.
Yes, by rearranging the position of the comment.
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.
Okay, cool. 👍
spotlessSelf.gradle
Outdated
include '**/*.gradle' | ||
exclude '_ext/**' | ||
} | ||
custom 'preventFormatPingPong', { return it.replaceAll('}[ \t\f]+}', '}}') } |
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 refactor the closure of the custom 'noInternalDeps', { ... }
step in the java { ... }
block above, into a variable, and pass that variable as a custom step to both the java
and groovy
blocks, like so:
spotless {
def noInternalDepsClosure = { source ->
if (source.contains('import org.gradle.internal.') {
throw new AssertionError("Accidental internal import")
}
}
java {
. . .
custom 'noInternalDeps', noInternalDepsClosure
. . .
}
groovy {
. . .
custom 'noInternalDeps', noInternalDepsClosure
. . .
}
}
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.
👍
spotlessSelf.gradle
Outdated
include '**/*.gradle' | ||
exclude '_ext/**' | ||
} | ||
custom 'preventFormatPingPong', { return it.replaceAll('}[ \t\f]+}', '}}') } |
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.
And then please add the following line just below
bumpThisNumberIfACustomStepChanges(1)
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.
👍
spotlessSelf.gradle
Outdated
include '**/*.gradle' | ||
exclude '_ext/**' | ||
} | ||
custom 'preventFormatPingPong', { return it.replaceAll('}[ \t\f]+}', '}}') } |
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 mildly curious by the \f
here, as it's a unusual regex pattern for me. What does it match against?
Would matching against \t
as well be sensible 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 \t should be sensible, since it will most likely to the ping-pong as well. But yes the \f should be removed.
testlib/build.gradle
Outdated
@@ -13,6 +13,5 @@ dependencies { | |||
} | |||
|
|||
// we'll hold the testlib to a low standard (prize brevity) | |||
findbugs { | |||
reportLevel = 'high' // low|medium|high (low = sensitive to even minor mistakes) | |||
findbugs { reportLevel = 'high' // low|medium|high (low = sensitive to even minor mistakes) | |||
} |
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's not clear to me why Greclipse formatted this section like this.
Can we prevent it with a setting?
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.
No, just by rearranging the position of the comment.
@jbduncan So in summary, you think using greclipse for spotless gradle is principally ok? Shall I provide a new proposal within this PR, or shall we split this issue? |
… greclipse formatter)
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 @fvgh! Two minor things left.
spotlessSelf.gradle
Outdated
@@ -6,18 +6,19 @@ plugins { | |||
|
|||
repositories { jcenter() } | |||
spotless { | |||
def noInternalDepsClosure = { | |||
if (it.contains('import org.gradle.internal.') && | |||
!it.contains('def noInternalDepsClosure')) { |
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 think this condition does little if anything to help here.
With this condition in place, it means that if we format spotlessSelf.gradle
, then it will never throw AssertionError
even if it imports org.gradle.internal.*
. I don't know if build files can even import Gradle-internal packages, but we might as well play it safe I reckon.
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.
Oh, I'm most likely mistaken!
I can see that if !it.contains('def noInternalDepsClosure')
is not in place, then running spotlessSelf.gradle
on itself would cause an AssertionError
.
Never mind! 😝
spotlessSelf.gradle
Outdated
@@ -28,7 +29,9 @@ spotless { | |||
include '**/*.gradle' | |||
exclude '_ext/**' | |||
} | |||
custom 'noInternalDeps', noInternalDepsClosure | |||
custom 'preventFormatPingPong', { return it.replaceAll('}[ \t\f]+}', '}}') } |
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.
Are you still working on replacing \f
with \t
?
@nedtwigg Let me know what you would propose about using greclipse to format the gradle files. As soon as we reach a final agreement, I'll do quickly the cherry-picking and squash the commits. |
I am afraid the testing for this PR under Windows are not yet successful. Provide a solution later on. |
…ct to test. Omit implicit testing of end-line characters for licenseHeader step.
EXCLUDE_JAVA_DEFAULT was being used as an alias for `false`. If we changed its value to true, it didn't just change the default behavior, it would also break the implementation logic.
…enCentral as well.
…an reference it directly.
The DSL should be based on the name of the project. Many formatters have "format" in the name -> google-java-format, scalafmt, etc. But others don't, e.g. ktlint.
@@ -77,6 +77,7 @@ lib('scala.ScalaFmtStep') +'{{yes}} | {{no}} | |||
+ implementing up-to-date checking [#31](https://github.com/diffplug/spotless/issues/31) | |||
+ breaking spotless into libraries [#56](https://github.com/diffplug/spotless/issues/56) | |||
+ lots of other things, but especially the diff support in `spotlessCheck` | |||
* Huge thanks to [Frank Vennemeyer](https://github.com/fvgh) for [Groovy support via greclipse](https://github.com/diffplug/spotless/issues/13). | |||
* Huge thanks to [Stefan Oehme](https://github.com/oehme) for tons of help on the internal mechanics of Gradle. |
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.
@fvgh do you have a different homepage you'd like me to link to?
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, the page is fine.
This looks great!!! I'm ready to merge and release. I made a few changes and updated the changelog. Once I get signoff from you that my changes are okay, we can ship it! |
Btw, just a note:
PaddedCell can resolve any ambiguity. For converging sequences, it will just silently let it slide. For cycles and diverging sequences, the user has to manually specify |
I squashed the commits. |
Merged!! I unsquashed them. We've done some merge commits along the way, so squashing made the history confusing to look at (we still couldn't do a simple rebase). Also, I tagged one of the intermittent commits as the commit which released to mavenCentral. The merge commit does a nice job providing a summary of all the changes. It should be in oss.snapshots in ~10 minutes, we'll make sure it's doing what we want, and then I'll ship 3.0.0! |
Errr, 3.3.0 |
Supporting dedicated configuration for groovy source.
The configuration allows access to formatter steps which have been introduced for Java, but which are also useable for Groovy code.
Integrates Groovy-Eclipse based Groovy formatter step implementation.
Allows coexistent configuration of Java and Groovy formatter steps.