Skip to content

Commit f5bfb34

Browse files
authored
Respect .editorconfig settings for formatting shell via shfmt (#2031)
2 parents 47d2c0f + 6e52d6e commit f5bfb34

File tree

22 files changed

+277
-24
lines changed

22 files changed

+277
-24
lines changed

.github/workflows/ci.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ jobs:
5757
- kind: npm
5858
jre: 11
5959
os: ubuntu-latest
60+
- kind: shfmt
61+
jre: 11
62+
os: ubuntu-latest
63+
shfmt-version: 3.7.0
6064
runs-on: ${{ matrix.os }}
6165
steps:
6266
- name: Checkout
@@ -79,6 +83,14 @@ jobs:
7983
- name: test npm
8084
if: matrix.kind == 'npm'
8185
run: ./gradlew testNpm
86+
- name: Install shfmt
87+
if: matrix.kind == 'shfmt'
88+
run: |
89+
curl -sSfL "https://github.com/mvdan/sh/releases/download/v${{ matrix.shfmt-version }}/shfmt_v${{ matrix.shfmt-version }}_linux_amd64" -o /usr/local/bin/shfmt
90+
chmod +x /usr/local/bin/shfmt
91+
- name: Test shfmt
92+
if: matrix.kind == 'shfmt'
93+
run: ./gradlew testShfmt
8294
- name: junit result
8395
uses: mikepenz/action-junit-report@v4
8496
if: always() # always run even if the previous step fails

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
1212
## [Unreleased]
1313
### Added
1414
* `FileSignature.Promised` and `JarState.Promised` to facilitate round-trip serialization for the Gradle configuration cache. ([#1945](https://github.com/diffplug/spotless/pull/1945))
15+
* Respect `.editorconfig` settings for formatting shell via `shfmt` ([#2031](https://github.com/diffplug/spotless/pull/2031))
16+
1517
### Removed
1618
* **BREAKING** Remove `JarState.getMavenCoordinate(String prefix)`. ([#1945](https://github.com/diffplug/spotless/pull/1945))
1719
* **BREAKING** Replace `PipeStepPair` with `FenceStep`. ([#1954](https://github.com/diffplug/spotless/pull/1954))

lib/src/main/java/com/diffplug/spotless/shell/ShfmtStep.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import java.util.List;
2323
import java.util.Objects;
2424
import java.util.regex.Pattern;
25+
import java.util.stream.Collectors;
26+
import java.util.stream.Stream;
2527

2628
import javax.annotation.Nullable;
2729

@@ -72,7 +74,7 @@ private State createState() throws IOException, InterruptedException {
7274
"\n github issue to handle this better: https://github.com/diffplug/spotless/issues/673";
7375
final ForeignExe exe = ForeignExe.nameAndVersion("shfmt", version)
7476
.pathToExe(pathToExe)
75-
.versionRegex(Pattern.compile("(\\S*)"))
77+
.versionRegex(Pattern.compile("([\\d.]+)"))
7678
.fixCantFind(howToInstall)
7779
.fixWrongVersion(
7880
"You can tell Spotless to use the version you already have with {@code shfmt('{versionFound}')}" +
@@ -83,9 +85,11 @@ private State createState() throws IOException, InterruptedException {
8385
@SuppressFBWarnings("SE_TRANSIENT_FIELD_NOT_RESTORED")
8486
static class State implements Serializable {
8587
private static final long serialVersionUID = -1825662356883926318L;
88+
8689
// used for up-to-date checks and caching
8790
final String version;
8891
final transient ForeignExe exe;
92+
8993
// used for executing
9094
private transient @Nullable List<String> args;
9195

@@ -96,10 +100,16 @@ static class State implements Serializable {
96100

97101
String format(ProcessRunner runner, String input, File file) throws IOException, InterruptedException {
98102
if (args == null) {
99-
args = List.of(exe.confirmVersionAndGetAbsolutePath(), "-i", "2", "-ci");
103+
// args will be reused during a single Spotless task execution,
104+
// so this "prefix" is being "cached" for each Spotless format with shfmt.
105+
args = List.of(exe.confirmVersionAndGetAbsolutePath(), "--filename");
100106
}
101107

102-
return runner.exec(input.getBytes(StandardCharsets.UTF_8), args).assertExitZero(StandardCharsets.UTF_8);
108+
// This will ensure that the next file name is retrieved on every format
109+
final List<String> finalArgs = Stream.concat(args.stream(), Stream.of(file.getAbsolutePath()))
110+
.collect(Collectors.toList());
111+
112+
return runner.exec(input.getBytes(StandardCharsets.UTF_8), finalArgs).assertExitZero(StandardCharsets.UTF_8);
103113
}
104114

105115
FormatterFunc.Closeable toFunc() {

plugin-gradle/CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
66
### Fixed
77
* Ignore system git config when running tests ([#1990](https://github.com/diffplug/spotless/issues/1990))
88

9+
### Added
10+
* Respect `.editorconfig` settings for formatting shell via `shfmt` ([#2031](https://github.com/diffplug/spotless/pull/2031))
11+
912
## [6.25.0] - 2024-01-23
1013
### Added
1114
* Maven / Gradle - Support for formatting Java Docs for the Palantir formatter ([#2009](https://github.com/diffplug/spotless/pull/2009))

plugin-gradle/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -992,7 +992,7 @@ spotless {
992992
```gradle
993993
spotless {
994994
shell {
995-
target 'scripts/**/*.sh' // default: '*.sh'
995+
target 'scripts/**/*.sh' // default: '**/*.sh'
996996
997997
shfmt() // has its own section below
998998
}
@@ -1003,11 +1003,15 @@ spotless {
10031003
10041004
[homepage](https://github.com/mvdan/sh). [changelog](https://github.com/mvdan/sh/blob/master/CHANGELOG.md).
10051005
1006+
When formatting shell scripts via `shfmt`, configure `shfmt` settings via `.editorconfig`.
1007+
Refer to the `shfmt` [man page](https://github.com/mvdan/sh/blob/master/cmd/shfmt/shfmt.1.scd) for `.editorconfig` settings.
1008+
10061009
```gradle
10071010
shfmt('3.7.0') // version is optional
10081011
10091012
// if shfmt is not on your path, you must specify its location manually
10101013
shfmt().pathToExe('/opt/homebrew/bin/shfmt')
1014+
10111015
// Spotless always checks the version of the shfmt it is using
10121016
// and will fail with an error if it does not match the expected version
10131017
// (whether manually specified or default). If there is a problem, Spotless

plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import com.diffplug.spotless.shell.ShfmtStep;
2424

2525
public class ShellExtension extends FormatExtension {
26-
private static final String SHELL_FILE_EXTENSION = "*.sh";
26+
private static final String SHELL_FILE_EXTENSION = "**/*.sh";
2727

2828
static final String NAME = "shell";
2929

plugin-gradle/src/test/java/com/diffplug/gradle/spotless/ShellExtensionTest.java

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,52 @@
2323

2424
@ShfmtTest
2525
public class ShellExtensionTest extends GradleIntegrationHarness {
26+
2627
@Test
27-
void shfmt() throws IOException {
28-
setFile("build.gradle").toLines(
28+
void shfmtWithEditorconfig() throws IOException {
29+
String fileDir = "shell/shfmt/with-config/";
30+
31+
setFile("build.gradle.kts").toLines(
2932
"plugins {",
30-
" id 'com.diffplug.spotless'",
33+
" id(\"com.diffplug.spotless\")",
3134
"}",
3235
"spotless {",
3336
" shell {",
3437
" shfmt()",
3538
" }",
3639
"}");
37-
setFile("shfmt.sh").toResource("shell/shfmt/shfmt.sh");
40+
41+
setFile(".editorconfig").toResource(fileDir + ".editorconfig");
42+
43+
setFile("shfmt.sh").toResource(fileDir + "shfmt.sh");
44+
setFile("scripts/other.sh").toResource(fileDir + "other.sh");
45+
3846
gradleRunner().withArguments("spotlessApply").build();
39-
assertFile("shfmt.sh").sameAsResource("shell/shfmt/shfmt.clean");
47+
48+
assertFile("shfmt.sh").sameAsResource(fileDir + "shfmt.clean");
49+
assertFile("scripts/other.sh").sameAsResource(fileDir + "other.clean");
50+
}
51+
52+
@Test
53+
void shfmtWithoutEditorconfig() throws IOException {
54+
String fileDir = "shell/shfmt/without-config/";
55+
56+
setFile("build.gradle.kts").toLines(
57+
"plugins {",
58+
" id(\"com.diffplug.spotless\")",
59+
"}",
60+
"spotless {",
61+
" shell {",
62+
" shfmt()",
63+
" }",
64+
"}");
65+
66+
setFile("shfmt.sh").toResource(fileDir + "shfmt.sh");
67+
setFile("scripts/other.sh").toResource(fileDir + "other.sh");
68+
69+
gradleRunner().withArguments("spotlessApply").build();
70+
71+
assertFile("shfmt.sh").sameAsResource(fileDir + "shfmt.clean");
72+
assertFile("scripts/other.sh").sameAsResource(fileDir + "other.clean");
4073
}
4174
}

plugin-maven/CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
66
### Fixed
77
* Ignore system git config when running tests ([#1990](https://github.com/diffplug/spotless/issues/1990))
88

9+
### Added
10+
* Respect `.editorconfig` settings for formatting shell via `shfmt` ([#2031](https://github.com/diffplug/spotless/pull/2031))
11+
912
## [2.43.0] - 2024-01-23
1013
### Added
1114
* Support for formatting shell scripts via [shfmt](https://github.com/mvdan/sh). ([#1998](https://github.com/diffplug/spotless/issues/1998))

plugin-maven/README.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1021,11 +1021,40 @@ Uses Jackson and YAMLFactory to pretty print objects:
10211021
</jackson>
10221022
```
10231023

1024+
## Shell
1025+
1026+
- `com.diffplug.spotless.maven.FormatterFactory.addStepFactory(FormatterStepFactory)` [code](./src/main/java/com/diffplug/spotless/maven/shell/Shell.java)
1027+
1028+
```xml
1029+
<configuration>
1030+
<shell>
1031+
<includes> <!-- Not required. Defaults to **/*.sh -->
1032+
<include>scripts/**/*.sh</include>
1033+
</includes>
1034+
1035+
<shfmt /> <!-- has its own section below -->
1036+
</shell>
1037+
</configuration>
1038+
```
1039+
1040+
### shfmt
1041+
1042+
[homepage](https://github.com/mvdan/sh). [changelog](https://github.com/mvdan/sh/blob/master/CHANGELOG.md).
1043+
1044+
When formatting shell scripts via `shfmt`, configure `shfmt` settings via `.editorconfig`.
1045+
1046+
```xml
1047+
<shfmt>
1048+
<version>3.7.0</version> <!-- optional: Custom version of 'mvdan/sh' -->
1049+
<pathToExe>/opt/homebrew/bin/shfmt</pathToExe> <!-- optional: if shfmt is not on your path, you must specify its location manually -->
1050+
</shfmt>
1051+
```
1052+
10241053
## Gherkin
10251054

10261055
- `com.diffplug.spotless.maven.FormatterFactory.addStepFactory(FormatterStepFactory)` [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/gherkin/Gherkin.java)
10271056

1028-
```gradle
1057+
```xml
10291058
<configuration>
10301059
<gherkin>
10311060
<includes> <!-- You have to set the target manually -->

plugin-maven/src/main/java/com/diffplug/spotless/maven/shell/Shell.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package com.diffplug.spotless.maven.shell;
1717

18-
import java.util.Collections;
1918
import java.util.Set;
2019

2120
import org.apache.maven.project.MavenProject;
@@ -30,9 +29,11 @@
3029
* and shell-specific (e.g. {@link Shfmt}) steps.
3130
*/
3231
public class Shell extends FormatterFactory {
32+
private static final Set<String> DEFAULT_INCLUDES = Set.of("**/*.sh");
33+
3334
@Override
3435
public Set<String> defaultIncludes(MavenProject project) {
35-
return Collections.emptySet();
36+
return DEFAULT_INCLUDES;
3637
}
3738

3839
@Override

0 commit comments

Comments
 (0)