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

Allow skipping targets based on text they contain #1749

Closed
wants to merge 2 commits into from
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2022 DiffPlug
* Copyright 2016-2023 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,18 +24,22 @@

final class FilterByContentPatternFormatterStep extends DelegateFormatterStep {
final Pattern contentPattern;
final boolean formatIfMatches;

FilterByContentPatternFormatterStep(FormatterStep delegateStep, String contentPattern) {
FilterByContentPatternFormatterStep(FormatterStep delegateStep, String contentPattern,
boolean formatIfMatches) {
super(delegateStep);
this.contentPattern = Pattern.compile(Objects.requireNonNull(contentPattern));
this.formatIfMatches = formatIfMatches;
}

@Override
public @Nullable String format(String raw, File file) throws Exception {
Objects.requireNonNull(raw, "raw");
Objects.requireNonNull(file, "file");
Matcher matcher = contentPattern.matcher(raw);
if (matcher.find()) {
boolean found = matcher.find();
if (formatIfMatches == found) {
return delegateStep.format(raw, file);
} else {
return raw;
Expand Down
16 changes: 15 additions & 1 deletion lib/src/main/java/com/diffplug/spotless/FormatterStep.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,21 @@ public interface FormatterStep extends Serializable {
* @return FormatterStep
*/
public default FormatterStep filterByContentPattern(String contentPattern) {
return new FilterByContentPatternFormatterStep(this, contentPattern);
return filterByContentPattern(contentPattern, true);
}
Comment on lines 56 to +58
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can update this one directly if you don't mind having an API change.


/**
* Returns a new {@code FormatterStep} which, observing the value of {@code formatIfMatches},
* will only apply, or not, its changes to files which pass the given filter.
*
* @param contentPattern
* java regular expression used to filter in or out files which content contain pattern
* @param formatIfMatches
* True to format only when {@code contentPattern} is found; false to format only when {@code contentPattern} is not found
* @return FormatterStep
*/
public default FormatterStep filterByContentPattern(String contentPattern, boolean formatIfMatches) {
return new FilterByContentPatternFormatterStep(this, contentPattern, formatIfMatches);
}

/**
Expand Down
2 changes: 2 additions & 0 deletions plugin-gradle/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (

## [Unreleased]

### Added
* Add target option `targetExcludeIfContentContains` to exclude files by text they contain.
### Fixed
* Correctly support the syntax
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ public void encoding(String charset) {
/** The files to be formatted = (target - targetExclude). */
protected FileCollection target, targetExclude;

/** The value from which files will be excluded if their content contain it. */
@Nullable
protected String targetExcludeIfContentContains = null;

protected boolean isLicenseHeaderStep(FormatterStep formatterStep) {
String formatterStepName = formatterStep.getName();

Expand Down Expand Up @@ -202,6 +206,11 @@ public void targetExclude(Object... targets) {
this.targetExclude = parseTargetsIsExclude(targets, true);
}

/** Excludes all files whose content contains {@code value}. */
public void targetExcludeIfContentContains(String value) {
this.targetExcludeIfContentContains = value;
}

private FileCollection parseTargetsIsExclude(Object[] targets, boolean isExclude) {
requireElementsNonNull(targets);
if (targets.length == 0) {
Expand Down Expand Up @@ -889,6 +898,9 @@ protected void setupTask(SpotlessTask task) {
} else {
steps = this.steps;
}
if (targetExcludeIfContentContains != null) {
steps.replaceAll(formatterStep -> formatterStep.filterByContentPattern(targetExcludeIfContentContains, false));
}
task.setSteps(steps);
task.setLineEndingsPolicy(getLineEndings().createPolicy(getProject().getProjectDir(), () -> totalTarget));
spotless.getRegisterDependenciesTask().hookSubprojectTask(task);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright 2020-2023 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.jupiter.api.Test;

class TargetExcludeIfContentContainsTest extends GradleIntegrationHarness {
@Test
void targetExcludeIfContentContainsWithOneValue() throws IOException {
setFile("build.gradle").toLines(
"plugins { id 'com.diffplug.spotless' }",
"spotless {",
" format 'toLower', {",
" target '**/*.md'",
" targetExcludeIfContentContains '// Generated by Mr. Roboto'",
" custom 'lowercase', { str -> str.toLowerCase() }",
" }",
"}");
String content = "// Generated by Mr. Roboto, do not edit.\n" +
"A B C\n" +
"D E F\n" +
"G H I";
setFile("test_generated.md").toContent(content);
setFile("test_manual.md").toLines(
"A B C",
"D E F",
"G H I");
gradleRunner().withArguments("spotlessApply").build();
// `test_generated` contains the excluding text so didn't change.
assertFile("test_generated.md").hasContent(content);
// `test_manual` does not so it changed.
assertFile("test_manual.md").hasLines(
"a b c",
"d e f",
"g h i");
}

@Test
void targetExcludeIfContentContainsWithMultipleSteps() throws IOException {
setFile("build.gradle").toLines(
"plugins { id 'com.diffplug.spotless' }",
"spotless {",
" format 'toLower', {",
" target '**/*.md'",
" targetExcludeIfContentContains '// Generated by Mr. Roboto'",
" custom 'lowercase', { str -> str.toLowerCase() }",
" licenseHeader('" + "// My CopyRights header" + "', '--')",
" }",
"}");
String generatedContent = "// Generated by Mr. Roboto, do not edit.\n" +
"--\n" +
"public final class MyMessage {}\n";
setFile("test_generated.md").toContent(generatedContent);
String manualContent = "// Typo in License\n" +
"--\n" +
"public final class MyMessage {\n" +
"}";
setFile("test_manual.md").toContent(manualContent);
gradleRunner().withArguments("spotlessApply").build();

// `test_generated` contains the excluding text so didn't change, including the header.
assertFile("test_generated.md").hasContent(generatedContent);
// `test_manual` does not, it changed.
assertFile("test_manual.md").hasContent(
"// My CopyRights header\n" +
"--\n" +
"public final class mymessage {\n" +
"}");
}

@Test
void targetExcludeIfContentContainsWithMultipleValues() throws IOException {
setFile("build.gradle").toLines(
"plugins { id 'com.diffplug.spotless' }",
"spotless {",
" format 'toLower', {",
" target '**/*.md'",
" targetExcludeIfContentContains '// Generated by Mr. Roboto|// Generated by Mrs. Call'",
" custom 'lowercase', { str -> str.toLowerCase() }",
" }",
"}");
String robotoContent = "A B C\n" +
"// Generated by Mr. Roboto, do not edit.\n" +
"D E F\n" +
"G H I";
setFile("test_generated_roboto.md").toContent(robotoContent);
String callContent = "A B C\n" +
"D E F\n" +
"// Generated by Mrs. Call, do not edit.\n" +
"G H I";
setFile("test_generated_call.md").toContent(callContent);
String collaborationContent = "A B C\n" +
"// Generated by Mr. Roboto, do not edit.\n" +
"D E F\n" +
"// Generated by Mrs. Call, do not edit.\n" +
"G H I";
setFile("test_generated_collaboration.md").toContent(collaborationContent);
String intruderContent = "A B C\n" +
"// Generated by K2000, do not edit.\n" +
"D E F\n" +
"G H I";
setFile("test_generated_intruder.md").toContent(intruderContent);
setFile("test_manual.md").toLines(
"A B C",
"D E F",
"G H I");
gradleRunner().withArguments("spotlessApply").build();
// Part of the excluding values so has not changed.
assertFile("test_generated_roboto.md").hasContent(robotoContent);
// Part of the excluding values so has not changed.
assertFile("test_generated_call.md").hasContent(callContent);
// Part of the excluding values so has not changed.
assertFile("test_generated_collaboration.md").hasContent(collaborationContent);
// Not part of the excluding values so has changed.
assertFile("test_generated_intruder.md").hasContent(
"a b c\n" +
"// generated by k2000, do not edit.\n" +
"d e f\n" +
"g h i");
// `test_manual` does not, it changed.
assertFile("test_manual.md").hasLines(
"a b c",
"d e f",
"g h i");
}
}