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 maven shell script formatting support via shfmt #1998

4 changes: 3 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ This document is intended for Spotless developers.
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).

## [Unreleased]
### Added
* Maven - Support for formatting shell scripts via [shfmt](https://github.com/mvdan/sh). ([#1998](https://github.com/diffplug/spotless/pull/1998))

## [2.44.0] - 2024-01-15
### Added
* New static method to `DiffMessageFormatter` which allows to retrieve diffs with their line numbers ([#1960](https://github.com/diffplug/spotless/issues/1960))
* Format shell via [shfmt](https://github.com/mvdan/sh). ([#1994](https://github.com/diffplug/spotless/pull/1994))
* Gradle - Support for formatting shell scripts via [shfmt](https://github.com/mvdan/sh). ([#1994](https://github.com/diffplug/spotless/pull/1994))
### Fixed
* Fix empty files with biome >= 1.5.0 when formatting files that are in the ignore list of the biome configuration file. ([#1989](https://github.com/diffplug/spotless/pull/1989) fixes [#1987](https://github.com/diffplug/spotless/issues/1987))
* Fix a regression in BufStep where the same arguments were being provided to every `buf` invocation. ([#1976](https://github.com/diffplug/spotless/issues/1976))
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ lib('pom.SortPomStepStep') +'{{no}} | {{yes}}
lib('protobuf.BufStep') +'{{yes}} | {{no}} | {{no}} | {{no}} |',
lib('python.BlackStep') +'{{yes}} | {{no}} | {{no}} | {{no}} |',
lib('scala.ScalaFmtStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |',
lib('shell.ShfmtStep') +'{{yes}} | {{no}} | {{no}} | {{no}} |',
lib('shell.ShfmtStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
lib('sql.DBeaverSQLFormatterStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |',
extra('wtp.EclipseWtpFormatterStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
lib('yaml.JacksonYamlStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
Expand Down Expand Up @@ -156,7 +156,7 @@ lib('yaml.JacksonYamlStep') +'{{yes}} | {{yes}}
| [`protobuf.BufStep`](lib/src/main/java/com/diffplug/spotless/protobuf/BufStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: |
| [`python.BlackStep`](lib/src/main/java/com/diffplug/spotless/python/BlackStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: |
| [`scala.ScalaFmtStep`](lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java) | :+1: | :+1: | :+1: | :white_large_square: |
| [`shell.ShfmtStep`](lib/src/main/java/com/diffplug/spotless/shell/ShfmtStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: |
| [`shell.ShfmtStep`](lib/src/main/java/com/diffplug/spotless/shell/ShfmtStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
| [`sql.DBeaverSQLFormatterStep`](lib/src/main/java/com/diffplug/spotless/sql/DBeaverSQLFormatterStep.java) | :+1: | :+1: | :+1: | :white_large_square: |
| [`wtp.EclipseWtpFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/wtp/EclipseWtpFormatterStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
| [`yaml.JacksonYamlStep`](lib/src/main/java/com/diffplug/spotless/yaml/JacksonYamlStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
Expand Down
12 changes: 7 additions & 5 deletions gradle/special-tests.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
apply plugin: 'com.adarshr.test-logger'

// See com.diffplug.spotless.tag package for available JUnit 5 @Tag annotations
def special = [
'Black',
'Buf',
Expand All @@ -9,10 +11,6 @@ def special = [

boolean isCiServer = System.getenv().containsKey("CI")
tasks.withType(Test).configureEach {
// See com.diffplug.spotless.tag package for available JUnit 5 @Tag annotations
useJUnitPlatform {
excludeTags special as String[]
}
if (isCiServer) {
retry {
maxRetries = 2
Expand All @@ -26,7 +24,11 @@ tasks.withType(Test).configureEach {
maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
}
}

tasks.named('test').configure {
useJUnitPlatform {
excludeTags special as String[]
}
}
special.forEach { tag ->
tasks.register("test${tag}", Test) {
useJUnitPlatform { includeTags tag }
Expand Down
2 changes: 1 addition & 1 deletion plugin-gradle/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (

## [6.24.0] - 2024-01-15
### Added
* Support for shell via [shfmt](https://github.com/mvdan/sh).
* Support for shell formatting via [shfmt](https://github.com/mvdan/sh). ([#1994](https://github.com/diffplug/spotless/pull/1994))
### Fixed
* Fix empty files with biome >= 1.5.0 when formatting files that are in the ignore list of the biome configuration file. ([#1989](https://github.com/diffplug/spotless/pull/1989) fixes [#1987](https://github.com/diffplug/spotless/issues/1987))=======
* Fix a regression in BufStep where the same arguments were being provided to every `buf` invocation. ([#1976](https://github.com/diffplug/spotless/issues/1976))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import com.diffplug.spotless.tag.ShfmtTest;

@ShfmtTest
public class ShfmtIntegrationTest extends GradleIntegrationHarness {
public class ShellExtensionTest extends GradleIntegrationHarness {
@Test
void shfmt() throws IOException {
setFile("build.gradle").toLines(
Expand Down
2 changes: 2 additions & 0 deletions plugin-maven/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).

## [Unreleased]
### Added
* Support for formatting shell scripts via [shfmt](https://github.com/mvdan/sh). ([#1998](https://github.com/diffplug/spotless/issues/1998))

## [2.42.0] - 2024-01-15
### Added
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 DiffPlug
* Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -73,6 +73,7 @@
import com.diffplug.spotless.maven.pom.Pom;
import com.diffplug.spotless.maven.python.Python;
import com.diffplug.spotless.maven.scala.Scala;
import com.diffplug.spotless.maven.shell.Shell;
import com.diffplug.spotless.maven.sql.Sql;
import com.diffplug.spotless.maven.typescript.Typescript;
import com.diffplug.spotless.maven.yaml.Yaml;
Expand Down Expand Up @@ -178,6 +179,9 @@ public abstract class AbstractSpotlessMojo extends AbstractMojo {
@Parameter
private Json json;

@Parameter
private Shell shell;

@Parameter
private Yaml yaml;

Expand Down Expand Up @@ -358,7 +362,7 @@ private FileLocator getFileLocator() {
}

private List<FormatterFactory> getFormatterFactories() {
return Stream.concat(formats.stream(), Stream.of(groovy, java, scala, kotlin, cpp, typescript, javascript, antlr4, pom, sql, python, markdown, json, yaml, gherkin))
return Stream.concat(formats.stream(), Stream.of(groovy, java, scala, kotlin, cpp, typescript, javascript, antlr4, pom, sql, python, markdown, json, shell, yaml, gherkin))
.filter(Objects::nonNull)
.collect(toList());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.diffplug.spotless.maven.shell;

import java.util.Collections;
import java.util.Set;

import org.apache.maven.project.MavenProject;

import com.diffplug.spotless.maven.FormatterFactory;
import com.diffplug.spotless.maven.generic.LicenseHeader;

/**
* A {@link FormatterFactory} implementation that corresponds to {@code <shell>...</shell>} configuration element.
* <p>
* It defines a formatter for shell source files that can execute both language agnostic (e.g. {@link LicenseHeader})
* and shell-specific (e.g. {@link Shfmt}) steps.
*/
public class Shell extends FormatterFactory {
@Override
public Set<String> defaultIncludes(MavenProject project) {
return Collections.emptySet();
}

@Override
public String licenseHeaderDelimiter() {
return null;
}

public void addShfmt(Shfmt shfmt) {
addStepFactory(shfmt);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.diffplug.spotless.maven.shell;

import org.apache.maven.plugins.annotations.Parameter;

import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.maven.FormatterStepConfig;
import com.diffplug.spotless.maven.FormatterStepFactory;
import com.diffplug.spotless.shell.ShfmtStep;

public class Shfmt implements FormatterStepFactory {

@Parameter
private String version;

@Parameter
private String pathToExe;

@Override
public FormatterStep newFormatterStep(FormatterStepConfig config) {
ShfmtStep shfmt = ShfmtStep.withVersion(version == null ? ShfmtStep.defaultVersion() : version);
if (pathToExe != null) {
shfmt = shfmt.withPathToExe(pathToExe);
}
return shfmt.create();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 DiffPlug
* Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -179,6 +179,10 @@ protected void writePomWithJsonSteps(String... steps) throws IOException {
writePom(groupWithSteps("json", including("**/*.json"), steps));
}

protected void writePomWithShellSteps(String... steps) throws IOException {
writePom(groupWithSteps("shell", including("**/*.sh"), steps));
}

protected void writePomWithYamlSteps(String... steps) throws IOException {
writePom(groupWithSteps("yaml", including("**/*.yaml"), steps));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.diffplug.spotless.maven.shell;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.diffplug.spotless.maven.MavenIntegrationHarness;
import com.diffplug.spotless.tag.ShfmtTest;

@ShfmtTest
public class ShellTest extends MavenIntegrationHarness {
private static final Logger LOGGER = LoggerFactory.getLogger(ShellTest.class);

@Test
public void testFormatShell() throws Exception {
writePomWithShellSteps("<shfmt/>");
setFile("shfmt.sh").toResource("shell/shfmt/shfmt.sh");
mavenRunner().withArguments("spotless:apply").runNoError();
assertFile("shfmt.sh").sameAsResource("shell/shfmt/shfmt.clean");
}
}