Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (

## [Unreleased]

### Added
* Added formatter for [Gherkin feature files](https://github.com/diffplug/spotless/issues/928)
* Added Gradle configuration for Gherkin feature files

## [2.16.0] - 2021-09-04
### Added
* Added support for `google-java-format`'s `skip-reflowing-long-strings` option ([#929](https://github.com/diffplug/spotless/pull/929))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2021 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.gherkin;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

import com.diffplug.spotless.FormatterFunc;
import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.JarState;
import com.diffplug.spotless.Provisioner;

public class GherkinSimpleStep {
private static final String MAVEN_COORDINATE = "me.jvt.cucumber:gherkin-formatter:";
private static final String DEFAULT_VERSION = "1.1.0";

public static FormatterStep create(int indent, Provisioner provisioner) {
Objects.requireNonNull(provisioner, "provisioner cannot be null");
return FormatterStep.createLazy("gherkin", () -> new GherkinSimpleStep.State(indent, provisioner), GherkinSimpleStep.State::toFormatter);
}

private static final class State implements Serializable {
private static final long serialVersionUID = 1L;

private final int indentSpaces;
private final JarState jarState;

private State(int indent, Provisioner provisioner) throws IOException {
this.indentSpaces = indent;
this.jarState = JarState.from(MAVEN_COORDINATE + DEFAULT_VERSION, provisioner);
}

FormatterFunc toFormatter() {
Method format;
Object formatter;
try {
ClassLoader classLoader = jarState.getClassLoader();
Class<?> prettyFormatter = classLoader.loadClass("me.jvt.cucumber.gherkinformatter.PrettyFormatter");
Class<?>[] constructorArguments = new Class[]{int.class};
Constructor<?> constructor = prettyFormatter.getConstructor(constructorArguments);
format = prettyFormatter.getMethod("format", String.class);
formatter = constructor.newInstance(indentSpaces);
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException(String.format("There was a problem preparing %s dependencies", MAVEN_COORDINATE), e);
}

return s -> {
try {
return (String) format.invoke(formatter, s);
} catch (InvocationTargetException ex) {
throw new AssertionError("Unable to format Gherkin", ex.getCause());
}
};
}
}

private GherkinSimpleStep() {
// cannot be directly instantiated
}
}
3 changes: 3 additions & 0 deletions plugin-gradle/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (

## [Unreleased]

### Added
* Added Gradle configuration for Gherkin feature files

## [5.15.0] - 2021-09-04
### Added
* Added support for `google-java-format`'s `skip-reflowing-long-strings` option ([#929](https://github.com/diffplug/spotless/pull/929))
Expand Down
29 changes: 29 additions & 0 deletions plugin-gradle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ Spotless supports all of Gradle's built-in performance features (incremental bui
- [SQL](#sql) ([dbeaver](#dbeaver), [prettier](#prettier))
- [Typescript](#typescript) ([tsfmt](#tsfmt), [prettier](#prettier))
- [JSON](#json)
- [Gherkin](#gherkin)
- Multiple languages
- [Prettier](#prettier) ([plugins](#prettier-plugins), [npm detection](#npm-detection), [`.npmrc` detection](#npmrc-detection))
- javascript, jsx, angular, vue, flow, typescript, css, less, scss, html, json, graphql, markdown, ymaml
Expand Down Expand Up @@ -558,6 +559,34 @@ spotless {
}
```

## Gherkin

- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/5.15.0/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java)

```gradle
spotless {
gherkin {
target 'src/**/*.feature' // you have to set the target manually
simple() // has its own section below
}
}
```

### simple

Uses a Gherkin pretty-printer that optionally allows configuring the number of spaces that are used to pretty print objects:

```gradle
spotless {
gherkin {
target 'src/**/*.feature'
simple()
// optional: specify the number of spaces to use
simple().indentWithSpaces(6)
}
}
```

<a name="applying-prettier-to-javascript--flow--typescript--css--scss--less--jsx--graphql--yaml--etc"></a>

## Prettier
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2016-2021 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.gradle.spotless;

import javax.inject.Inject;

import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.gherkin.GherkinSimpleStep;

public class GherkinExtension extends FormatExtension {
private static final int DEFAULT_INDENTATION = 4;
static final String NAME = "gherkin";

@Inject
public GherkinExtension(SpotlessExtension spotless) {
super(spotless);
}

@Override
protected void setupTask(SpotlessTask task) {
if (target == null) {
throw noDefaultTargetException();
}
super.setupTask(task);
}

public SimpleConfig simple() {
return new SimpleConfig(DEFAULT_INDENTATION);
}

public class SimpleConfig {
private int indent;

public SimpleConfig(int indent) {
this.indent = indent;
addStep(createStep());
}

public void indentWithSpaces(int indent) {
this.indent = indent;
replaceStep(createStep());
}

private FormatterStep createStep() {
return GherkinSimpleStep.create(indent, provisioner());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,12 @@ public void json(Action<JsonExtension> closure) {
format(JsonExtension.NAME, JsonExtension.class, closure);
}

/** Configures the special Gherkin-specific extension. */
public void gherkin(Action<GherkinExtension> closure) {
requireNonNull(closure);
format(GherkinExtension.NAME, GherkinExtension.class, closure);
}

/** Configures a custom extension. */
public void format(String name, Action<FormatExtension> closure) {
requireNonNull(name, "name");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2021 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.gradle.spotless;

import java.io.IOException;

import org.junit.Test;

public class GherkinExtensionTest extends GradleIntegrationHarness {
@Test
public void defaultFormatting() throws IOException {
setFile("build.gradle").toLines(
"buildscript { repositories { mavenCentral() } }",
"plugins {",
" id 'java'",
" id 'com.diffplug.spotless'",
"}",
"spotless {",
" gherkin {",
" target 'examples/**/*.feature'",
" simple()",
"}",
"}");
setFile("src/main/resources/example.feature").toResource("gherkin/minimalBefore.feature");
setFile("examples/main/resources/example.feature").toResource("gherkin/minimalBefore.feature");
gradleRunner().withArguments("spotlessApply").build();
assertFile("src/main/resources/example.feature").sameAsResource("gherkin/minimalBefore.feature");
assertFile("examples/main/resources/example.feature").sameAsResource("gherkin/minimalAfter.feature");
}

@Test
public void formattingWithCustomNumberOfSpaces() throws IOException {
setFile("build.gradle").toLines(
"buildscript { repositories { mavenCentral() } }",
"plugins {",
" id 'java'",
" id 'com.diffplug.spotless'",
"}",
"spotless {",
" gherkin {",
" target 'src/**/*.feature'",
" simple().indentWithSpaces(6)",
"}",
"}");
setFile("src/main/resources/example.feature").toResource("gherkin/minimalBefore.feature");
gradleRunner().withArguments("spotlessApply").build();
assertFile("src/main/resources/example.feature").sameAsResource("gherkin/minimalAfter6Spaces.feature");
}
}
24 changes: 24 additions & 0 deletions testlib/src/main/resources/gherkin/complex_backgroundAfter.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Feature: Complex background
We want to ensure PickleStep all have different IDs

Background: a simple background
Given the minimalism inside a background

Scenario: minimalistic
Given the minimalism

Scenario: also minimalistic
Given the minimalism

Rule: My Rule

Background:
Given a rule background step

Scenario: with examples
Given the <value> minimalism

Examples:
| value |
| 1 |
| 2 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Feature: Complex background
We want to ensure PickleStep all have different IDs

Background: a simple background
Given the minimalism inside a background

Scenario: minimalistic
Given the minimalism

Scenario: also minimalistic
Given the minimalism

Rule: My Rule

Background:
Given a rule background step

Scenario: with examples
Given the <value> minimalism

Examples:
| value |
| 1 |
| 2 |
47 changes: 47 additions & 0 deletions testlib/src/main/resources/gherkin/descriptionsAfter.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
Feature: Descriptions everywhere
This is a single line description

Scenario: two lines
This description
has two lines and indented with two spaces
Given the minimalism

Scenario: without indentation
This is a description without indentation
Given the minimalism

Scenario: empty lines in the middle
This description

has an empty line in the middle
Given the minimalism

Scenario: empty lines around
This description
has an empty lines around
Given the minimalism

Scenario: comment after description
This description
has a comment after
# this is a comment
Given the minimalism

Scenario: comment right after description
This description
has a comment right after
# this is another comment
Given the minimalism

Scenario: description with escaped docstring separator
This description has an \"\"\" (escaped docstring sparator)
Given the minimalism

Scenario Outline: scenario outline with a description
This is a scenario outline description
Given the minimalism

Examples: examples with description
This is an examples description
| foo |
| bar |
Loading