Skip to content

Commit

Permalink
Generate .gitattributes for Maven and Gradle
Browse files Browse the repository at this point in the history
Closes gh-1569
  • Loading branch information
mhalbritter committed Oct 16, 2024
1 parent c0e18b8 commit 6b2774d
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* 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
*
* https://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 io.spring.initializr.generator.spring.scm.git;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* Project's {@code .gitattributes}.
*
* @author Moritz Halbritter
*/
public class GitAttributes {

private final List<Line> lines = new ArrayList<>();

/**
* Adds a new pattern with attributes.
* @param pattern the pattern
* @param attribute the first attribute
* @param remainingAttributes the remaining attributes
*/
public void add(String pattern, String attribute, String... remainingAttributes) {
List<String> attributes = new ArrayList<>();
attributes.add(attribute);
attributes.addAll(Arrays.asList(remainingAttributes));
this.lines.add(new Line(pattern, attributes));
}

void write(PrintWriter writer) {
for (Line line : this.lines) {
line.write(writer);
}
}

boolean isEmpty() {
return this.lines.isEmpty();
}

private record Line(String pattern, List<String> attributes) {
void write(PrintWriter writer) {
writer.print(this.pattern);
writer.print(' ');
writer.print(String.join(" ", this.attributes));
writer.println();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* 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
*
* https://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 io.spring.initializr.generator.spring.scm.git;

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;

import io.spring.initializr.generator.project.contributor.ProjectContributor;

/**
* A {@link ProjectContributor} that contributes a {@code .gitattributes} file to a
* project.
*
* @author Moritz Halbritter
*/
public class GitAttributesContributor implements ProjectContributor {

private final GitAttributes gitAttributes;

public GitAttributesContributor(GitAttributes gitAttributes) {
this.gitAttributes = gitAttributes;
}

@Override
public void contribute(Path projectRoot) throws IOException {
if (this.gitAttributes.isEmpty()) {
return;
}
Path file = Files.createFile(projectRoot.resolve(".gitattributes"));
try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(file))) {
this.gitAttributes.write(writer);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* 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
*
* https://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 io.spring.initializr.generator.spring.scm.git;

import org.springframework.core.Ordered;

/**
* Callback for customizing a project's {@link GitAttributes}. Invoked with an
* {@link Ordered order} of {@code 0} by default, considering overriding
* {@link #getOrder()} to customize this behaviour.
*
* @author Moritz Halbritter
*/
@FunctionalInterface
public interface GitAttributesCustomizer extends Ordered {

void customize(GitAttributes gitAttributes);

@Override
default int getOrder() {
return 0;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,9 @@
import java.nio.file.Path;

import io.spring.initializr.generator.project.contributor.ProjectContributor;
import io.spring.initializr.generator.project.contributor.SingleResourceProjectContributor;

/**
* A {@link SingleResourceProjectContributor} that contributes a {@code .gitignore} file
* to a project.
* A {@link ProjectContributor} that contributes a {@code .gitignore} file to a project.
*
* @author Andy Wilkinson
* @author Stephane Nicoll
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
*
* @author Andy Wilkinson
* @author Stephane Nicoll
* @author Moritz Halbritter
*/
@ProjectGenerationConfiguration
public class GitProjectGenerationConfiguration {
Expand All @@ -45,6 +46,18 @@ public GitIgnore gitIgnore(ObjectProvider<GitIgnoreCustomizer> gitIgnoreCustomiz
return gitIgnore;
}

@Bean
GitAttributesContributor gitAttributesContributor(GitAttributes gitAttributes) {
return new GitAttributesContributor(gitAttributes);
}

@Bean
GitAttributes gitAttributes(ObjectProvider<GitAttributesCustomizer> gitAttributesCustomizers) {
GitAttributes gitAttributes = new GitAttributes();
gitAttributesCustomizers.orderedStream().forEach((customizer) -> customizer.customize(gitAttributes));
return gitAttributes;
}

@Bean
@ConditionalOnBuildSystem(MavenBuildSystem.ID)
public GitIgnoreCustomizer mavenGitIgnoreCustomizer() {
Expand All @@ -68,6 +81,25 @@ public GitIgnoreCustomizer gradleGitIgnoreCustomizer() {
};
}

@Bean
@ConditionalOnBuildSystem(MavenBuildSystem.ID)
public GitAttributesCustomizer mavenGitAttributesCustomizer() {
return (gitAttributes) -> {
gitAttributes.add("/mvnw", "text", "eol=lf");
gitAttributes.add("*.cmd", "text", "eol=crlf");
};
}

@Bean
@ConditionalOnBuildSystem(GradleBuildSystem.ID)
public GitAttributesCustomizer gradleGitAttributesCustomizer() {
return (gitAttributes) -> {
gitAttributes.add("/gradlew", "text", "eol=lf");
gitAttributes.add("*.bat", "text", "eol=crlf");
gitAttributes.add("*.jar", "binary");
};
}

private GitIgnore createGitIgnore() {
GitIgnore gitIgnore = new GitIgnore();
gitIgnore.getSts()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ void customBaseDirectoryIsUsedWhenGeneratingProject() {
description.setBaseDirectory("test/demo-app");
ProjectStructure project = this.projectTester.generate(description);
assertThat(project).filePaths()
.containsOnly("test/demo-app/.gitignore", "test/demo-app/pom.xml", "test/demo-app/mvnw",
"test/demo-app/mvnw.cmd", "test/demo-app/.mvn/wrapper/maven-wrapper.properties",
.containsOnly("test/demo-app/.gitignore", "test/demo-app/.gitattributes", "test/demo-app/pom.xml",
"test/demo-app/mvnw", "test/demo-app/mvnw.cmd",
"test/demo-app/.mvn/wrapper/maven-wrapper.properties",
"test/demo-app/src/main/java/com/example/demo/DemoApplication.java",
"test/demo-app/src/main/resources/application.properties",
"test/demo-app/src/test/java/com/example/demo/DemoApplicationTests.java", "test/demo-app/HELP.md");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* 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
*
* https://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 io.spring.initializr.generator.spring.scm.git;

import java.io.PrintWriter;
import java.io.StringWriter;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Tests for {@link GitAttributes}.
*
* @author Moritz Halbritter
*/
class GitAttributesTests {

@Test
void shouldWriteGitAttributes() {
GitAttributes attributes = new GitAttributes();
attributes.add("/gradlew", "text", "eof=lf");
attributes.add("*.bat", "text", "eol=crlf");
attributes.add("*.jar", "binary");
String written = writeToString(attributes);
assertThat(written).isEqualToNormalizingNewlines("""
/gradlew text eof=lf
*.bat text eol=crlf
*.jar binary
""");
}

private String writeToString(GitAttributes attributes) {
StringWriter stringWriter = new StringWriter();
try (PrintWriter printWriter = new PrintWriter(stringWriter)) {
attributes.write(printWriter);
}
return stringWriter.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
* Tests for {@link GitProjectGenerationConfiguration}.
*
* @author Stephane Nicoll
* @author Moritz Halbritter
*/
class GitProjectGenerationConfigurationTests {

Expand Down Expand Up @@ -85,11 +86,55 @@ void gitIgnoreMaven() {
.doesNotContain(".gradle", "!gradle/wrapper/gradle-wrapper.jar", "/out/");
}

@Test
void gitAttributesIsContributedToProject(@TempDir Path directory) {
MutableProjectDescription description = new MutableProjectDescription();
description.setBuildSystem(new GradleBuildSystem());
Path projectDirectory = this.projectTester.withDirectory(directory).generate(description, (context) -> {
GitAttributesContributor contributor = context.getBean(GitAttributesContributor.class);
contributor.contribute(directory);
return directory;
});
assertThat(projectDirectory.resolve(".gitattributes")).isRegularFile();
}

@Test
void gitAttributesGradle() {
MutableProjectDescription description = new MutableProjectDescription();
description.setBuildSystem(new GradleBuildSystem());
description.setPlatformVersion(Version.parse("3.4.0"));
assertThat(generateGitAttributes(description))
.contains("/gradlew text eol=lf", "*.bat text eol=crlf", "*.jar binary")
.doesNotContain("/mvnw text eol=lf", "*.cmd text eol=crlf");
}

@Test
void gitAttributesMaven() {
MutableProjectDescription description = new MutableProjectDescription();
description.setBuildSystem(new MavenBuildSystem());
description.setPlatformVersion(Version.parse("3.3.0"));
assertThat(generateGitAttributes(description)).contains("/mvnw text eol=lf", "*.cmd text eol=crlf")
.doesNotContain("/gradlew text eol=lf", "*.bat text eol=crlf", "*.jar binary");
}

private List<String> generateGitIgnore(MutableProjectDescription description) {
return this.projectTester.generate(description, (context) -> {
GitIgnore gitIgnore = context.getBean(GitIgnore.class);
StringWriter out = new StringWriter();
gitIgnore.write(new PrintWriter(out));
try (PrintWriter printWriter = new PrintWriter(out)) {
gitIgnore.write(printWriter);
}
return TextTestUtils.readAllLines(out.toString());
});
}

private List<String> generateGitAttributes(MutableProjectDescription description) {
return this.projectTester.generate(description, (context) -> {
GitAttributes gitAttributes = context.getBean(GitAttributes.class);
StringWriter out = new StringWriter();
try (PrintWriter printWriter = new PrintWriter(out)) {
gitAttributes.write(printWriter);
}
return TextTestUtils.readAllLines(out.toString());
});
}
Expand Down

0 comments on commit 6b2774d

Please sign in to comment.