- * The header includes all lines until the first section {@code ##} starts.
- *
+ * Get a list of sections (starting with a ## heading).
*
- * @return list of lines of the header
+ * @return list of sections
*/
- public List getHeaderSectionLines() {
- return this.headerSectionLines;
+ public List getSections() {
+ return this.sections;
}
/**
- * Get a list of sections (starting with a ## heading).
+ * Get the dependency change section.
+ *
+ * @return dependency change section
+ */
+ public Optional getDependencyChangeSection() {
+ return Optional.ofNullable(dependencyChangeSection);
+ }
+
+ /**
+ * Get the summary section.
*
- * @return list of sections
+ * @return summary section
*/
- public List getSections() {
- return this.sections;
+ public Optional getSummarySection() {
+ return Optional.ofNullable(this.summarySection);
+ }
+
+ @Override
+ public String toString() {
+ return "ChangesFile [projectName=" + projectName + ", projectVersion=" + projectVersion + ", releaseDate="
+ + releaseDate + ", codeName=" + codeName + ", summarySection=" + summarySection + ", sections="
+ + sections + ", dependencyChangeSection=" + dependencyChangeSection + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(projectName, projectVersion, releaseDate, codeName, summarySection, sections,
+ dependencyChangeSection);
}
@Override
@@ -133,31 +168,23 @@ public boolean equals(final Object obj) {
}
final ChangesFile other = (ChangesFile) obj;
return Objects.equals(projectName, other.projectName) && Objects.equals(projectVersion, other.projectVersion)
- && Objects.equals(releaseDate, other.releaseDate)
- && Objects.equals(headerSectionLines, other.headerSectionLines)
- && Objects.equals(sections, other.sections);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(projectName, projectVersion, releaseDate, headerSectionLines, sections);
- }
-
- @Override
- public String toString() {
- return String.join("\n", this.headerSectionLines) + "\n"
- + this.sections.stream().map(ChangesFileSection::toString).collect(Collectors.joining("\n"));
+ && Objects.equals(releaseDate, other.releaseDate) && Objects.equals(codeName, other.codeName)
+ && Objects.equals(summarySection, other.summarySection) && Objects.equals(sections, other.sections)
+ && Objects.equals(dependencyChangeSection, other.dependencyChangeSection);
}
/**
* Builder for {@link ChangesFile}.
*/
public static class Builder {
+
private String projectName;
private Semver projectVersion;
private String releaseDate;
+ private String codeName;
+ private ChangesFileSection summarySection;
private List sections = new ArrayList<>();
- private List header = Collections.emptyList();
+ private ChangesFileSection dependencyChangeSection;
private Builder() {
// private constructor to hide public default
@@ -197,24 +224,44 @@ public Builder releaseDate(final String releaseDate) {
}
/**
- * Set the header of the changes file.
+ * Set the code name of the release.
*
- * @param header list of lines
+ * @param codeName code name
* @return self for fluent programming
*/
- public Builder setHeader(final List header) {
- this.header = header;
+ public Builder codeName(final String codeName) {
+ this.codeName = codeName.isBlank() ? null : codeName;
return this;
}
/**
* Add a section to the changes file.
*
- * @param lines list of lines
+ * @param section section
* @return self for fluent programming
*/
- public Builder addSection(final List lines) {
- this.sections.add(new ChangesFileSection(lines));
+ public Builder addSection(final ChangesFileSection section) {
+ this.sections.add(section);
+ return this;
+ }
+
+ /**
+ * Set the {@code Summary} section for the changes file.
+ *
+ * @param section section
+ * @return self for fluent programming
+ */
+ public Builder summary(final ChangesFileSection section) {
+ if (section == null) {
+ this.summarySection = null;
+ return this;
+ }
+ if (!section.getHeading().equals(SUMMARY_HEADING)) {
+ throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-178").message(
+ "Dependency change section has invalid heading {{heading}}, expected {{expected heading}}",
+ section.getHeading(), SUMMARY_HEADING).ticketMitigation().toString());
+ }
+ this.summarySection = section;
return this;
}
@@ -229,6 +276,26 @@ public Builder sections(final List sections) {
return this;
}
+ /**
+ * Add a an optional {@code Dependency Updates} section to the changes file.
+ *
+ * @param section section
+ * @return self for fluent programming
+ */
+ public Builder dependencyChangeSection(final ChangesFileSection section) {
+ if (section == null) {
+ this.dependencyChangeSection = null;
+ return this;
+ }
+ if (!section.getHeading().equals(DEPENDENCY_UPDATES_HEADING)) {
+ throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-178").message(
+ "Dependency change section has invalid heading {{heading}}, expected {{expected heading}}",
+ section.getHeading(), DEPENDENCY_UPDATES_HEADING).ticketMitigation().toString());
+ }
+ this.dependencyChangeSection = section;
+ return this;
+ }
+
/**
* Build the {@link ChangesFile}.
*
@@ -237,5 +304,6 @@ public Builder sections(final List sections) {
public ChangesFile build() {
return new ChangesFile(this);
}
+
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java
index 90f4be3c..07aa3acd 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java
@@ -2,8 +2,7 @@
import java.io.*;
import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -14,6 +13,7 @@
* This class reads and writes a {@link ChangesFile} from disk.
*/
public class ChangesFileIO {
+ private static final String CODE_NAME = "Code name:";
private static final String PROJECT_NAME_PATTERN = "[\\w\\s-]+";
private static final String VERSION_PATTERN = "\\d+\\.\\d+\\.\\d+";
private static final String DATE_PATTERN = "\\d{4}-[\\d?]{2}-[\\d?]{2}";
@@ -39,50 +39,84 @@ public ChangesFile read(final Path file) {
}
ChangesFile read(final Path file, final BufferedReader fileReader) throws IOException {
- String sectionHeader = null;
- String line;
- int lineCount = 0;
- final var builder = ChangesFile.builder();
+ return new Parser(file, fileReader).parse();
+ }
+
+ private static class Parser {
+ final Path file;
+ final BufferedReader reader;
+ final Builder builder = ChangesFile.builder();
+ ChangesFileSection.Builder currentSection;
+
final List lineBuffer = new ArrayList<>();
- while ((line = fileReader.readLine()) != null) {
+ int lineCount = 0;
+
+ Parser(final Path file, final BufferedReader reader) {
+ this.file = file;
+ this.reader = reader;
+ }
+
+ ChangesFile parse() throws IOException {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ parseLine(line);
+ lineCount++;
+ }
+ addSection();
+ return builder.build();
+ }
+
+ private void parseLine(final String line) {
if (lineCount == 0) {
- parseFirstLine(file, line, builder);
- } else {
- if (SECTION_HEADING_PATTERN.matcher(line).matches()) {
- makeSection(sectionHeader, builder, lineBuffer);
- sectionHeader = line;
- }
- lineBuffer.add(line);
+ parseFirstLine(file, line);
+ return;
+ }
+ if (line.startsWith(CODE_NAME)) {
+ builder.codeName(line.substring(CODE_NAME.length()).trim());
+ return;
+ }
+ if (line.startsWith("## ")) {
+ addSection();
+ currentSection = ChangesFileSection.builder(line);
+ return;
+ }
+ if (currentSection != null) {
+ currentSection.addLine(line);
}
- lineCount++;
}
- makeSection(sectionHeader, builder, lineBuffer);
- return builder.build();
- }
- private void parseFirstLine(final Path filePath, final String line, final Builder builder) {
- final Matcher matcher = FIRST_LINE_PATTERN.matcher(line);
- if (!matcher.matches()) {
- throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-171")
- .message("Changes file {{file path}} contains invalid first line {{first line}}.", filePath, line)
- .mitigation("Update first line so that it matches regex {{expected regular expression}}",
- FIRST_LINE_PATTERN)
- .toString());
+ private void addSection() {
+ if (currentSection == null) {
+ return;
+ }
+ final ChangesFileSection section = currentSection.build();
+ currentSection = null;
+ switch (section.getHeading()) {
+ case ChangesFile.SUMMARY_HEADING:
+ builder.summary(section);
+ break;
+ case ChangesFile.DEPENDENCY_UPDATES_HEADING:
+ builder.dependencyChangeSection(section);
+ break;
+ default:
+ builder.addSection(section);
+ break;
+ }
}
- builder.projectName(matcher.group(1)) //
- .projectVersion(matcher.group(2)) //
- .releaseDate(matcher.group(3));
- }
- private void makeSection(final String sectionHeader, final ChangesFile.Builder builder,
- final List lineBuffer) {
- if (!lineBuffer.isEmpty()) {
- if (sectionHeader == null) {
- builder.setHeader(List.copyOf(lineBuffer));
- } else {
- builder.addSection(List.copyOf(lineBuffer));
+ private void parseFirstLine(final Path filePath, final String line) {
+ final Matcher matcher = FIRST_LINE_PATTERN.matcher(line);
+ if (!matcher.matches()) {
+ throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-171")
+ .message("Changes file {{file path}} contains invalid first line {{first line}}.", filePath,
+ line)
+ .mitigation("Update first line so that it matches regex {{expected regular expression}}",
+ FIRST_LINE_PATTERN)
+ .toString());
}
- lineBuffer.clear();
+ builder.projectName(matcher.group(1)) //
+ .projectVersion(matcher.group(2)) //
+ .releaseDate(matcher.group(3));
}
}
@@ -104,23 +138,38 @@ public void write(final ChangesFile changesFile, final Path destinationFile) {
}
void write(final ChangesFile changesFile, final Writer writer) throws IOException {
- writeFirstLine(writer, changesFile);
- writeSection(writer, changesFile.getHeaderSectionLines());
+ writeHeader(writer, changesFile);
for (final ChangesFileSection section : changesFile.getSections()) {
- writeSection(writer, section.getContent());
+ writeSection(writer, section);
+ }
+ final Optional dependencyChangeSection = changesFile.getDependencyChangeSection();
+ if (dependencyChangeSection.isPresent()) {
+ writer.write(dependencyChangeSection.get().toString());
+ writer.write(LINE_SEPARATOR);
}
}
- private void writeFirstLine(final Writer writer, final ChangesFile changesFile) throws IOException {
+ private void writeHeader(final Writer writer, final ChangesFile changesFile) throws IOException {
writer.write("# " + changesFile.getProjectName() + " " + changesFile.getProjectVersion() + ", released "
+ changesFile.getReleaseDate());
writer.write(LINE_SEPARATOR);
+ writer.write(LINE_SEPARATOR);
+ writer.write(CODE_NAME + (changesFile.getCodeName() != null ? " " + changesFile.getCodeName() : ""));
+ writer.write(LINE_SEPARATOR);
+ writer.write(LINE_SEPARATOR);
+ final Optional summarySection = changesFile.getSummarySection();
+ if (summarySection.isPresent()) {
+ writer.write(summarySection.get().toString());
+ writer.write(LINE_SEPARATOR);
+ }
}
- private void writeSection(final Writer fileWriter, final List content) throws IOException {
- for (final String line : content) {
- fileWriter.write(line);
- fileWriter.write(LINE_SEPARATOR);
+ private void writeSection(final Writer writer, final ChangesFileSection section) throws IOException {
+ writer.write(section.getHeading());
+ writer.write(LINE_SEPARATOR);
+ for (final String line : section.getContent()) {
+ writer.write(line);
+ writer.write(LINE_SEPARATOR);
}
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java
index 26a27080..9a71af5a 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java
@@ -1,9 +1,8 @@
package com.exasol.projectkeeper.validators.changesfile;
-import java.util.List;
-import java.util.Objects;
+import static java.util.Arrays.asList;
-import com.exasol.errorreporting.ExaError;
+import java.util.*;
/**
* Section of a {@link ChangesFile}.
@@ -12,19 +11,13 @@
*
*/
public final class ChangesFileSection {
+
+ private final String heading;
private final List content;
- /**
- * Create a new instance of {@link ChangesFileSection}.
- *
- * @param content lines
- */
- public ChangesFileSection(final List content) {
- if (content.isEmpty()) {
- throw new IllegalStateException(ExaError.messageBuilder("F-PK-CORE-36")
- .message("changes file sections must not be empty.").ticketMitigation().toString());
- }
- this.content = List.copyOf(content);
+ private ChangesFileSection(final Builder builder) {
+ this.heading = Objects.requireNonNull(builder.heading, "header");
+ this.content = List.copyOf(builder.lines);
}
/**
@@ -33,7 +26,7 @@ public ChangesFileSection(final List content) {
* @return heading
*/
public String getHeading() {
- return this.content.get(0);
+ return this.heading;
}
/**
@@ -46,22 +39,60 @@ public List getContent() {
}
@Override
- public boolean equals(final Object other) {
- if (this == other)
- return true;
- if (other == null || getClass() != other.getClass())
- return false;
- final ChangesFileSection that = (ChangesFileSection) other;
- return Objects.equals(this.content, that.content);
+ public int hashCode() {
+ return Objects.hash(heading, content);
}
@Override
- public int hashCode() {
- return Objects.hash(this.content);
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ChangesFileSection other = (ChangesFileSection) obj;
+ return Objects.equals(heading, other.heading) && Objects.equals(content, other.content);
}
@Override
public String toString() {
- return String.join("\n", this.content);
+ return heading + "\n" + String.join("\n", this.content);
+ }
+
+ public static Builder builder(final String heading) {
+ return new Builder(heading);
+ }
+
+ public static class Builder {
+
+ private final String heading;
+ private final List lines = new ArrayList<>();
+
+ private Builder(final String heading) {
+ this.heading = heading;
+ }
+
+ public Builder addLines(final String... lines) {
+ this.lines.addAll(asList(lines));
+ return this;
+ }
+
+ public Builder addLines(final List lines) {
+ this.lines.addAll(lines);
+ return this;
+ }
+
+ public Builder addLine(final String line) {
+ this.lines.add(line);
+ return this;
+ }
+
+ public ChangesFileSection build() {
+ return new ChangesFileSection(this);
+ }
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java
index db520196..ba21db83 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java
@@ -74,8 +74,11 @@ private ChangesFile fixSections(final ChangesFile changesFile) {
private ChangesFile getTemplate() {
final String releaseDate = LocalDateTime.now().getYear() + "-??-??";
final var changesFile = ChangesFile.builder().projectName(this.projectName).projectVersion(this.projectVersion)
- .releaseDate(releaseDate).setHeader(List.of("", "Code name:", "")) //
- .addSection(List.of("## Summary", "", "## Features", "", "* ISSUE_NUMBER: description", "")) //
+ .releaseDate(releaseDate) //
+ .codeName("") //
+ .summary(ChangesFileSection.builder("## Summary").build())
+ .addSection(ChangesFileSection.builder("## Features").addLines("", "* ISSUE_NUMBER: description", "")
+ .build()) //
.build();
return fixSections(changesFile);
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java
index 60f4ddf9..9db14cf0 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java
@@ -1,9 +1,7 @@
package com.exasol.projectkeeper.validators.changesfile;
-import static com.exasol.projectkeeper.validators.changesfile.ChangesFile.DEPENDENCY_UPDATES_HEADING;
-
-import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import java.util.stream.Collectors;
import com.exasol.projectkeeper.sources.AnalyzedSource;
@@ -35,20 +33,12 @@ public DependencySectionFixer(final List sources) {
public ChangesFile fix(final ChangesFile changesFile) {
final List reports = this.sources.stream().map(this::getDependencyChangesOfSource)
.collect(Collectors.toList());
- final List renderedReport = new DependencyChangeReportRenderer().render(reports);
- final List sections = new ArrayList<>(changesFile.getSections());
- removeDependencySection(sections);
- if (!renderedReport.isEmpty()) {
- sections.add(new ChangesFileSection(renderedReport));
- }
- return changesFile.toBuilder().sections(sections).build();
+ final Optional dependencyChanges = new DependencyChangeReportRenderer().render(reports);
+ return changesFile.toBuilder() //
+ .dependencyChangeSection(dependencyChanges.orElse(null)).build();
}
private NamedDependencyChangeReport getDependencyChangesOfSource(final AnalyzedSource source) {
return new NamedDependencyChangeReport(source.getProjectName(), source.getDependencyChanges());
}
-
- private void removeDependencySection(final List sections) {
- sections.removeIf(section -> section.getHeading().compareToIgnoreCase(DEPENDENCY_UPDATES_HEADING) == 0);
- }
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java
index aca0d23d..34695e34 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java
@@ -2,14 +2,12 @@
import static com.exasol.projectkeeper.ApStyleFormatter.capitalizeApStyle;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
import com.exasol.projectkeeper.shared.dependencies.BaseDependency.Type;
import com.exasol.projectkeeper.shared.dependencychanges.DependencyChange;
import com.exasol.projectkeeper.shared.dependencychanges.DependencyChangeReport;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
-import com.exasol.projectkeeper.validators.changesfile.NamedDependencyChangeReport;
+import com.exasol.projectkeeper.validators.changesfile.*;
/**
* String renderer for {@link DependencyChangeReport}.
@@ -20,17 +18,15 @@ public class DependencyChangeReportRenderer {
* Render a {@link DependencyChangeReport} to string.
*
* @param reports reports to render
- * @return rendered report as a list of lines
+ * @return rendered report as a section
*/
- public List render(final List reports) {
+ public Optional render(final List reports) {
final List content = renderContent(reports);
- final List lines = new ArrayList<>();
if (content.isEmpty()) {
- return lines;
+ return Optional.empty();
}
- lines.add(ChangesFile.DEPENDENCY_UPDATES_HEADING);
- lines.addAll(content);
- return lines;
+ return Optional.of(ChangesFileSection.builder(ChangesFile.DEPENDENCY_UPDATES_HEADING) //
+ .addLines(content).build());
}
private List renderContent(final List reports) {
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java
index 4971e431..cc140a7c 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java
@@ -15,6 +15,8 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import com.github.hamstercommunity.matcher.auto.AutoMatcher;
+
class ChangesFileIOTest {
@TempDir
Path tempDir;
@@ -29,20 +31,23 @@ void testParsing() throws IOException {
assertThat(changesFile.getProjectVersion().toString(), equalTo("0.1.0"));
assertThat(changesFile.getReleaseDate(), equalTo("1980-01-01"));
assertThat(changesFile.getParsedReleaseDate().get(), equalTo(LocalDate.parse("1980-01-01")));
- assertThat(headings, contains("## Summary", "## Features", "## Bug Fixes", "## Documentation", "## Refactoring",
- "## Dependency Updates"));
+ assertThat(changesFile.getSummarySection().get().getContent(), contains("", "My summary", ""));
+ assertThat(headings, contains("## Features", "## Bug Fixes", "## Documentation", "## Refactoring"));
+ assertThat(changesFile.getDependencyChangeSection().get().getHeading(), equalTo("## Dependency Updates"));
+ assertThat(changesFile.getDependencyChangeSection().get().getContent(), hasSize(18));
}
@Test
void testWriting() throws IOException {
final ChangesFile changesFile = ChangesFile.builder().projectName("project").projectVersion("1.2.3")
- .releaseDate("2023-??-??").setHeader(List.of("# MyChanges")).addSection(List.of("## My Subsection"))
- .build();
+ .releaseDate("2023-??-??").codeName("my code name")
+ .summary(ChangesFileSection.builder("## Summary").addLine("my summary content").build())
+ .addSection(ChangesFileSection.builder("# MyChanges").build())
+ .addSection(ChangesFileSection.builder("## My Subsection").addLine("content").build()).build();
final Path testFile = this.tempDir.resolve("myFile.md");
new ChangesFileIO().write(changesFile, testFile);
- assertThat(Files.readString(testFile), equalTo("# project 1.2.3, released 2023-??-??" + System.lineSeparator() + //
- "# MyChanges" + System.lineSeparator() + //
- "## My Subsection" + System.lineSeparator()));
+ assertThat(Files.readString(testFile), equalTo(
+ "# project 1.2.3, released 2023-??-??\n\nCode name: my code name\n\n## Summary\nmy summary content\n# MyChanges\n## My Subsection\ncontent\n"));
}
@Test
@@ -61,17 +66,19 @@ void testReadInvalidFirstLineFails() {
@Test
void testReadFirstLineWithDummyReleaseDate() throws IOException {
- final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-??-??");
+ final ChangesFile changesFile = readFromString(
+ "# Project Name 1.2.3, released 2024-??-??\nCode name: my code name\n## Summary\n\n");
assertThat(changesFile.getProjectName(), equalTo("Project Name"));
assertThat(changesFile.getProjectVersion().toString(), equalTo("1.2.3"));
assertThat(changesFile.getReleaseDate(), equalTo("2024-??-??"));
+ assertThat(changesFile.getCodeName(), equalTo("my code name"));
assertThat(changesFile.getParsedReleaseDate().isPresent(), is(false));
assertWriteRead(changesFile);
}
@Test
void testReadFirstLineWithValidReleaseDate() throws IOException {
- final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29");
+ final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29\n## Summary\n\n");
assertThat(changesFile.getProjectName(), equalTo("Project Name"));
assertThat(changesFile.getProjectVersion().toString(), equalTo("1.2.3"));
assertThat(changesFile.getReleaseDate(), equalTo("2024-01-29"));
@@ -79,6 +86,45 @@ void testReadFirstLineWithValidReleaseDate() throws IOException {
assertWriteRead(changesFile);
}
+ @Test
+ void testReadMissingSummary() throws IOException {
+ final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29");
+ assertThat(changesFile.getSummarySection().isEmpty(), is(true));
+ }
+
+ @Test
+ void testReadEmptySummary() throws IOException {
+ final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29\n## Summary");
+ final ChangesFileSection summary = changesFile.getSummarySection().get();
+ assertThat(summary.getHeading(), equalTo("## Summary"));
+ assertThat(summary.getContent(), emptyIterable());
+ }
+
+ @Test
+ void testReadSummary() throws IOException {
+ final ChangesFile changesFile = readFromString(
+ "# Project Name 1.2.3, released 2024-01-29\n## Summary\nmy\ncontent\n");
+ final ChangesFileSection summary = changesFile.getSummarySection().get();
+ assertThat(summary.getHeading(), equalTo("## Summary"));
+ assertThat(summary.getContent(), contains("my", "content"));
+ assertWriteRead(changesFile);
+ }
+
+ @Test
+ void testReadNoDependencySection() throws IOException {
+ final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29\n## Summary");
+ assertThat(changesFile.getDependencyChangeSection().isEmpty(), is(true));
+ }
+
+ @Test
+ void testReadDependencySection() throws IOException {
+ final ChangesFile changesFile = readFromString(
+ "# Project Name 1.2.3, released 2024-01-29\n## Summary\n## Dependency Updates\nmy\ncontent");
+ assertThat(changesFile.getDependencyChangeSection().isEmpty(), is(false));
+ assertThat(changesFile.getDependencyChangeSection().get().getHeading(), equalTo("## Dependency Updates"));
+ assertThat(changesFile.getDependencyChangeSection().get().getContent(), contains("my", "content"));
+ }
+
private Path loadExampleFileToTempDir() throws IOException {
final Path changesFile = this.tempDir.resolve("changed_0.1.0.md");
try (final InputStream exampleFileStream = getExampleFileStream()) {
@@ -100,6 +146,8 @@ private InputStream getExampleFileStream() {
private void assertWriteRead(final ChangesFile changesFile) throws IOException {
final String content = writeToString(changesFile);
final ChangesFile readChangesFile = readFromString(content);
+ assertThat(readChangesFile.toString(), equalTo(changesFile.toString()));
+ assertThat(readChangesFile, AutoMatcher.equalTo(changesFile));
assertThat(readChangesFile, equalTo(changesFile));
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java
index e8fff56f..86701f2f 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java
@@ -6,11 +6,11 @@
import java.nio.file.Path;
import java.time.LocalDate;
-import java.util.List;
import org.junit.jupiter.api.Test;
import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder;
+import com.jparams.verifier.tostring.ToStringVerifier;
import nl.jqno.equalsverifier.EqualsVerifier;
@@ -21,6 +21,11 @@ void equalsContract() {
EqualsVerifier.forClass(ChangesFile.class).verify();
}
+ @Test
+ void testToString() {
+ ToStringVerifier.forClass(ChangesFile.class).verify();
+ }
+
@Test
void getPathForVersion() {
assertThat(ChangesFile.getPathForVersion("1.2.3"), equalTo(Path.of("doc/changes/changes_1.2.3.md")));
@@ -36,7 +41,8 @@ void toBuilderCreatesCopy() {
private Builder builder() {
return ChangesFile.builder().projectName("name").projectVersion("1.2.3").releaseDate("2023-??-??")
- .addSection(List.of("section 1")).setHeader(List.of("header 1"));
+ .summary(ChangesFileSection.builder("## Summary").build())
+ .addSection(ChangesFileSection.builder("section 1").build());
}
@Test
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java
index 5eca082b..62234975 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java
@@ -33,7 +33,7 @@
class ChangesFileValidatorTest {
private static final String A_VERSION = "1.2.3";
private static final String A_PROJECT_NAME = "my-project";
- private static final String LINE_SEPARATOR = System.lineSeparator();
+ private static final String LINE_SEPARATOR = "\n";
@TempDir
Path tempDir;
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java
index f9391bba..d02f8e7f 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java
@@ -2,8 +2,7 @@
import static com.exasol.projectkeeper.validators.changesfile.ChangesFile.DEPENDENCY_UPDATES_HEADING;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.*;
import java.util.List;
@@ -33,33 +32,43 @@ static void beforeAll() {
@Test
void testSectionIsAdded() {
- final ChangesFile changesFile = changesFileBuilder().setHeader(List.of("heading")).build();
- final List sections = new DependencySectionFixer(List.of(source)).fix(changesFile)
- .getSections();
- assertThat(sections.size(), equalTo(1));
- assertThat(sections.get(0).getHeading(), equalTo(DEPENDENCY_UPDATES_HEADING));
+ final ChangesFile changesFile = changesFileBuilder().addSection(ChangesFileSection.builder("heading").build())
+ .build();
+ final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile);
+ assertThat(fixedChangesFile.getDependencyChangeSection().get().getHeading(),
+ equalTo(DEPENDENCY_UPDATES_HEADING));
}
private Builder changesFileBuilder() {
- return ChangesFile.builder().projectName("projectName").projectVersion("1.2.3").releaseDate("releaseDate");
+ return ChangesFile.builder().projectName("projectName").projectVersion("1.2.3").releaseDate("releaseDate")
+ .summary(ChangesFileSection.builder("## Summary").build());
}
@Test
void testSectionIsUpdated() {
- final ChangesFile changesFile = changesFileBuilder().setHeader(List.of("heading"))
- .addSection(List.of(DEPENDENCY_UPDATES_HEADING, "myLine")).build();
+ final ChangesFile changesFile = changesFileBuilder().dependencyChangeSection(
+ ChangesFileSection.builder("## Dependency Updates").addLine("content will be overwritten").build())
+ .build();
final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile);
- final List sections = fixedChangesFile.getSections();
- assertThat(sections.size(), equalTo(1));
- assertThat(sections.get(0).getHeading(), equalTo(DEPENDENCY_UPDATES_HEADING));
- assertThat("dependency fixer changed the changes file", changesFile, not(equalTo(fixedChangesFile)));
+ final ChangesFileSection changesFileSection = fixedChangesFile.getDependencyChangeSection().get();
+ assertThat(changesFileSection.getHeading(), equalTo(DEPENDENCY_UPDATES_HEADING));
+ assertThat(changesFileSection.getContent(),
+ contains("", "### Compile Dependency Updates", "", "* Added `com.example:my-lib:1.2.3`"));
+ assertThat("dependency fixer changed the changes file", changesFile,
+ allOf(not(equalTo(fixedChangesFile)), not(sameInstance(fixedChangesFile))));
}
@Test
- void testHeaderIsPreserved() {
- final ChangesFile changesFile = changesFileBuilder().setHeader(List.of("heading"))
- .addSection(List.of(DEPENDENCY_UPDATES_HEADING, "myLine")).build();
- final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile);
- assertThat(changesFile.getHeaderSectionLines(), equalTo(fixedChangesFile.getHeaderSectionLines()));
+ void testDependencySectionIsRemoved() {
+ final ChangesFile changesFile = changesFileBuilder().addSection(ChangesFileSection.builder("heading").build())
+ .dependencyChangeSection(ChangesFileSection.builder("## Dependency Updates")
+ .addLine("content will be preserved").build())
+ .build();
+ final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of()).fix(changesFile);
+
+ assertThat(fixedChangesFile.getDependencyChangeSection().isPresent(), is(false));
+ assertThat(fixedChangesFile, not(sameInstance(changesFile)));
+ assertThat("dependency fixer changed the changes file", changesFile,
+ allOf(not(equalTo(fixedChangesFile)), not(sameInstance(fixedChangesFile))));
}
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java
index 6ad5cde4..12eb1942 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java
@@ -1,16 +1,19 @@
package com.exasol.projectkeeper.validators.changesfile.dependencies;
+import static java.util.Arrays.asList;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.emptyString;
import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
import java.util.List;
+import java.util.Optional;
import org.junit.jupiter.api.Test;
import com.exasol.projectkeeper.shared.dependencies.BaseDependency.Type;
import com.exasol.projectkeeper.shared.dependencychanges.DependencyChangeReport;
import com.exasol.projectkeeper.shared.dependencychanges.NewDependency;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileSection;
import com.exasol.projectkeeper.validators.changesfile.NamedDependencyChangeReport;
class DependencyChangeReportRendererTest {
@@ -22,17 +25,15 @@ class DependencyChangeReportRendererTest {
@Test
void testRenderSingleSourceReport() {
final NamedDependencyChangeReport namedReport = new NamedDependencyChangeReport("my-project", REPORT);
- final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(namedReport)));
- assertThat(result, equalTo("## Dependency Updates\n" + "\n" + "### Compile Dependency Updates\n" + "\n"
- + "* Added `com.example:my-lib:1.2.3`"));
+ assertThat(render(namedReport), equalTo("## Dependency Updates\n" + "\n" + "### Compile Dependency Updates\n"
+ + "\n" + "* Added `com.example:my-lib:1.2.3`"));
}
@Test
void testRenderMultiSourceReport() {
final NamedDependencyChangeReport sourceA = new NamedDependencyChangeReport("project A", REPORT);
final NamedDependencyChangeReport sourceB = new NamedDependencyChangeReport("project B", REPORT);
- final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(sourceA, sourceB)));
- assertThat(result, equalTo(
+ assertThat(render(sourceA, sourceB), equalTo(
"## Dependency Updates\n\n### Project A\n\n#### Compile Dependency Updates\n\n* Added `com.example:my-lib:1.2.3`\n\n### Project B\n\n#### Compile Dependency Updates\n\n* Added `com.example:my-lib:1.2.3`"));
}
@@ -40,15 +41,20 @@ void testRenderMultiSourceReport() {
void testRenderMultiSourceReportWithNoChangesInOneReport() {
final NamedDependencyChangeReport sourceA = new NamedDependencyChangeReport("project A", REPORT);
final NamedDependencyChangeReport sourceB = new NamedDependencyChangeReport("project B", EMPTY_REPORT);
- final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(sourceA, sourceB)));
- assertThat(result, equalTo(
+ assertThat(render(sourceA, sourceB), equalTo(
"## Dependency Updates\n\n### Project A\n\n#### Compile Dependency Updates\n\n* Added `com.example:my-lib:1.2.3`"));
}
@Test
void testRenderSourceReportWithoutChanges() {
final NamedDependencyChangeReport sourceA = new NamedDependencyChangeReport("project A", EMPTY_REPORT);
- final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(sourceA)));
- assertThat(result, emptyString());
+ final Optional result = new DependencyChangeReportRenderer().render(List.of(sourceA));
+ assertThat(result.isPresent(), is(false));
}
-}
\ No newline at end of file
+
+ private String render(final NamedDependencyChangeReport... reports) {
+ final Optional section = new DependencyChangeReportRenderer().render(asList(reports));
+ assertThat(section.isPresent(), is(true));
+ return section.get().toString();
+ }
+}
diff --git a/project-keeper/src/test/resources/changesFileExample1.md b/project-keeper/src/test/resources/changesFileExample1.md
index 4791e2ef..49211dfd 100644
--- a/project-keeper/src/test/resources/changesFileExample1.md
+++ b/project-keeper/src/test/resources/changesFileExample1.md
@@ -49,4 +49,3 @@ My summary
* Added `::`
* Updated `::` to ``
* Removed `::`
-
From 1f01a2bb92ff19ecaccde5e239eb6a5783acc7ab Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 31 Jan 2024 11:49:52 +0100
Subject: [PATCH 42/78] Fix javadoc & error codes
---
parent-pom/error_code_config.yml | 8 +++++
.../dependencyupdate/DependencyUpdater.java | 2 --
.../validators/changesfile/ChangesFile.java | 2 +-
.../changesfile/ChangesFileSection.java | 33 ++++++++++++++++++-
4 files changed, 41 insertions(+), 4 deletions(-)
create mode 100644 parent-pom/error_code_config.yml
diff --git a/parent-pom/error_code_config.yml b/parent-pom/error_code_config.yml
new file mode 100644
index 00000000..1389755e
--- /dev/null
+++ b/parent-pom/error_code_config.yml
@@ -0,0 +1,8 @@
+# This file is only used for release guide.
+# Actual error codes are based on files error_code_config.yml in individual subfolders.
+
+error-tags:
+ PK-PARENT:
+ packages:
+ - dummy
+ highest-index: 1
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
index 5dcb5121..293a7475 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
@@ -33,8 +33,6 @@ public class DependencyUpdater {
/**
* Create a new instance.
*
- * @param projectKeeper
- *
* @param projectKeeper project keeper reference
* @param logger the logger to which we should write log messages
* @param projectDir the project directory
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
index b9d695f7..d95e836e 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
@@ -288,7 +288,7 @@ public Builder dependencyChangeSection(final ChangesFileSection section) {
return this;
}
if (!section.getHeading().equals(DEPENDENCY_UPDATES_HEADING)) {
- throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-178").message(
+ throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-179").message(
"Dependency change section has invalid heading {{heading}}, expected {{expected heading}}",
section.getHeading(), DEPENDENCY_UPDATES_HEADING).ticketMitigation().toString());
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java
index 9a71af5a..5e5a1ac1 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java
@@ -63,12 +63,20 @@ public String toString() {
return heading + "\n" + String.join("\n", this.content);
}
+ /**
+ * Create a new {@link Builder} for creating a {@link ChangesFileSection}.
+ *
+ * @param heading the heading for the new section
+ * @return a new builder
+ */
public static Builder builder(final String heading) {
return new Builder(heading);
}
+ /**
+ * A builder for creating {@link ChangesFileSection}s.
+ */
public static class Builder {
-
private final String heading;
private final List lines = new ArrayList<>();
@@ -76,21 +84,44 @@ private Builder(final String heading) {
this.heading = heading;
}
+ /**
+ * Add the given lines to the content of the new {@code ChangesFileSection}.
+ *
+ * @param lines lines to add
+ * @return {@code this} for fluent programming
+ */
public Builder addLines(final String... lines) {
this.lines.addAll(asList(lines));
return this;
}
+ /**
+ * Add the given lines to the content of the new {@code ChangesFileSection}.
+ *
+ * @param lines lines to add
+ * @return {@code this} for fluent programming
+ */
public Builder addLines(final List lines) {
this.lines.addAll(lines);
return this;
}
+ /**
+ * Add the given line to the content of the new {@code ChangesFileSection}.
+ *
+ * @param line line to add
+ * @return {@code this} for fluent programming
+ */
public Builder addLine(final String line) {
this.lines.add(line);
return this;
}
+ /**
+ * Build a new {@link ChangesFileSection}.
+ *
+ * @return a new {@link ChangesFileSection}.
+ */
public ChangesFileSection build() {
return new ChangesFileSection(this);
}
From 678ab3160e8a28b3fd17f908a3e00d50430ef087 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 31 Jan 2024 13:21:40 +0100
Subject: [PATCH 43/78] Remove unwanted import
---
.../validators/changesfile/ChangesFileIOTest.java | 3 ---
1 file changed, 3 deletions(-)
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java
index cc140a7c..5da24627 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java
@@ -15,8 +15,6 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
-import com.github.hamstercommunity.matcher.auto.AutoMatcher;
-
class ChangesFileIOTest {
@TempDir
Path tempDir;
@@ -147,7 +145,6 @@ private void assertWriteRead(final ChangesFile changesFile) throws IOException {
final String content = writeToString(changesFile);
final ChangesFile readChangesFile = readFromString(content);
assertThat(readChangesFile.toString(), equalTo(changesFile.toString()));
- assertThat(readChangesFile, AutoMatcher.equalTo(changesFile));
assertThat(readChangesFile, equalTo(changesFile));
}
From e144e11b72262a85d1ed75a8db92d2b00557d41d Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 31 Jan 2024 15:29:26 +0100
Subject: [PATCH 44/78] Refactor project crawler runner
---
maven-project-crawler/error_code_config.yml | 2 +-
.../MavenProjectCrawlerMojo.java | 5 +
.../JavaProjectCrawlerRunner.java | 93 ++++++-------------
.../analyze/generic/MavenProcessBuilder.java | 26 +++++-
4 files changed, 58 insertions(+), 68 deletions(-)
diff --git a/maven-project-crawler/error_code_config.yml b/maven-project-crawler/error_code_config.yml
index 867099b3..cf122110 100644
--- a/maven-project-crawler/error_code_config.yml
+++ b/maven-project-crawler/error_code_config.yml
@@ -2,4 +2,4 @@ error-tags:
PK-MPC:
packages:
- com.exasol.projectkeeper
- highest-index: 63
\ No newline at end of file
+ highest-index: 64
diff --git a/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java b/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java
index f8266227..85cc9ec6 100644
--- a/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java
+++ b/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java
@@ -39,6 +39,11 @@ public class MavenProjectCrawlerMojo extends AbstractMojo {
// [impl -> dsn~eclipse-prefs-java-version~1]
@Override
public void execute() {
+ if (projectsToCrawl == null || projectsToCrawl.isBlank()) {
+ throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-MPC-64")
+ .message("Property {{property name}} is not defined or empty.", PROPERTY_PROJECTS_TO_CRAWL)
+ .mitigation("Specify property with least one pom file.").toString());
+ }
final MavenProjectFromFileReader mavenProjectReader = new DefaultMavenProjectFromFileReader(
this.mavenProjectBuilder, this.session);
final MavenModelFromRepositoryReader modelFromRepositoryReader = new MavenModelFromRepositoryReader(
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java
index e8aa3ecd..18dcf1ed 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java
@@ -1,37 +1,28 @@
package com.exasol.projectkeeper;
-import java.io.IOException;
-import java.io.UncheckedIOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
import java.util.stream.Collectors;
-import com.exasol.errorreporting.ExaError;
import com.exasol.projectkeeper.shared.mavenprojectcrawler.MavenProjectCrawlResult;
import com.exasol.projectkeeper.shared.mavenprojectcrawler.ResponseCoder;
import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder;
-import com.exasol.projectkeeper.stream.AsyncStreamReader;
-import com.exasol.projectkeeper.stream.CollectingConsumer;
+import com.exasol.projectkeeper.sources.analyze.generic.SimpleProcess;
/**
* Runs the maven plugin goal on the current repository and returns the parsed result.
*/
public class JavaProjectCrawlerRunner {
- private static final Logger LOGGER = Logger.getLogger(JavaProjectCrawlerRunner.class.getName());
- private static final Duration STREAM_READING_TIMEOUT = Duration.ofSeconds(1);
private final Path mvnRepositoryOverride;
private final String ownVersion;
/**
* Create a new instance of {@link JavaProjectCrawlerRunner}.
*
- * @param mvnRepositoryOverride maven repository override. Use {@code null} for default
+ * @param mvnRepositoryOverride Maven repository override. This is useful for running integration tests. Use
+ * {@code null} for default.
* @param ownVersion project-keeper version
*/
public JavaProjectCrawlerRunner(final Path mvnRepositoryOverride, final String ownVersion) {
@@ -51,63 +42,39 @@ public MavenProjectCrawlResult crawlProject(final Path... pomFiles) {
}
private String runCrawlerPlugin(final Path... pomFiles) {
- final String projectList = Arrays.stream(pomFiles).map(pomFile -> pomFile.toAbsolutePath().toString()
- // we use / instead of \ here as a fix for https://github.com/eclipse-ee4j/yasson/issues/540
- .replace(FileSystems.getDefault().getSeparator(), "/")).collect(Collectors.joining(";"));
- final List commandParts = buildMavenCommand(projectList);
- LOGGER.fine(() -> "Executing command " + commandParts);
- try {
- final Process proc = new ProcessBuilder(commandParts).redirectErrorStream(true).start();
-
- final CollectingConsumer outputStreamConsumer = new AsyncStreamReader()
- .startCollectingConsumer(proc.getInputStream());
- final CollectingConsumer errorStreamConsumer = new AsyncStreamReader()
- .startCollectingConsumer(proc.getErrorStream());
-
- if (!proc.waitFor(90, TimeUnit.SECONDS)) {
- final String stdOutput = outputStreamConsumer.getCurrentContent();
- final String stdError = errorStreamConsumer.getCurrentContent();
- throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-81").message(
- "Timeout while executing command {{executed command|u}}. Output: {{std output}}, error: {{std error}}",
- commandParts, stdOutput, stdError).toString());
- }
- final int exitCode = proc.exitValue();
- final String output = outputStreamConsumer.getContent(STREAM_READING_TIMEOUT);
- if (exitCode != 0) {
- LOGGER.log(Level.SEVERE, output);
- throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-78").message(
- "Failed to run command {{executed command|u}}, exit code was {{exit code}}. Output:\n{{output}}",
- commandParts, exitCode, output).toString());
- }
- return new ResponseCoder().decodeResponse(output);
- } catch (final IOException exception) {
- throw new UncheckedIOException(getRunFailedMessage(), exception);
- } catch (final InterruptedException exception) {
- Thread.currentThread().interrupt();
- throw new IllegalStateException(getRunFailedMessage(), exception);
- }
+ final MavenProcessBuilder builder = buildMavenCommand(pomFiles);
+ final SimpleProcess process = builder.startSimpleProcess();
+ process.waitUntilFinished(Duration.ofSeconds(90));
+ return new ResponseCoder().decodeResponse(process.getOutputStreamContent());
}
- private List buildMavenCommand(final String projectList) {
- final MavenProcessBuilder command = MavenProcessBuilder.create().addArguments("--batch-mode",
- "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn",
- "com.exasol:project-keeper-java-project-crawler:" + this.ownVersion + ":" + "crawl",
- "-DprojectsToCrawl=" + projectList,
- /*
- * We need to disable the model cache here since it caches the parent poms with {revision} as version
- * and then runs into trouble since the cache is different when reading the old pom (for comparing
- * dependencies).
- */
- "-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true");
+ private MavenProcessBuilder buildMavenCommand(final Path... pomFiles) {
+ final MavenProcessBuilder builder = MavenProcessBuilder.create()
+ .addArguments(
+ "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn",
+ "com.exasol:project-keeper-java-project-crawler:" + this.ownVersion + ":" + "crawl",
+ "-DprojectsToCrawl=" + getProjectList(pomFiles),
+ /*
+ * We need to disable the model cache here since it caches the parent poms with {revision} as
+ * version and then runs into trouble since the cache is different when reading the old pom (for
+ * comparing dependencies).
+ */
+ "-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true")
+ .workingDir(null);
if (this.mvnRepositoryOverride != null) {
- command.addArgument("-Dmaven.repo.local=" + this.mvnRepositoryOverride);
+ builder.addArgument("-Dmaven.repo.local=" + this.mvnRepositoryOverride);
}
- return command.build();
+ return builder;
}
- private String getRunFailedMessage() {
- return ExaError.messageBuilder("E-PK-CORE-80").message("Failed to run project-keeper-java-project-crawler.")
- .toString();
+ private String getProjectList(final Path... pomFiles) {
+ return Arrays.stream(pomFiles).map(this::formatPath).collect(Collectors.joining(";"));
+ }
+
+ private String formatPath(final Path pomFile) {
+ return pomFile.toAbsolutePath().toString()
+ // we use / instead of \ here as a fix for https://github.com/eclipse-ee4j/yasson/issues/540
+ .replace(FileSystems.getDefault().getSeparator(), "/");
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
index c546567d..cfbf386b 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
@@ -2,8 +2,11 @@
import static java.util.Arrays.asList;
+import java.nio.file.Path;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
+import java.util.logging.Logger;
import com.exasol.projectkeeper.OsCheck;
import com.exasol.projectkeeper.OsCheck.OSType;
@@ -13,7 +16,10 @@
*/
public class MavenProcessBuilder {
+ private static final Logger LOG = Logger.getLogger(MavenProcessBuilder.class.getName());
+ private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(30);
private final List command = new ArrayList<>();
+ private Path workingDir = null;
private MavenProcessBuilder() {
// Use create() method
@@ -27,6 +33,7 @@ private MavenProcessBuilder() {
public static MavenProcessBuilder create() {
final MavenProcessBuilder builder = new MavenProcessBuilder();
builder.addArgument(getMavenExecutable());
+ builder.addArgument("--batch-mode");
return builder;
}
@@ -53,12 +60,23 @@ public MavenProcessBuilder addArgument(final String argument) {
}
/**
- * Build the command that can be used as argument for {@link ProcessBuilder}.
+ * Define the working directory where to execute the command. Default: {@code null}.
*
- * @return the command
+ * @param workingDir working dir
+ * @return {@code this} for fluent programming
+ */
+ public MavenProcessBuilder workingDir(final Path workingDir) {
+ this.workingDir = workingDir;
+ return this;
+ }
+
+ /**
+ * Build the command and run it.
+ *
+ * @return the running {@link SimpleProcess}
*/
- public List build() {
- return List.copyOf(this.command);
+ public SimpleProcess startSimpleProcess() {
+ return SimpleProcess.start(workingDir, command);
}
private static String getMavenExecutable() {
From a62cee9092164263fc49fd59586e9ac2fa8b27f0 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 31 Jan 2024 15:29:54 +0100
Subject: [PATCH 45/78] Update references after incrementing the version
---
...nProjectWithProjectKeeperPluginWriter.java | 14 +++++
.../plugin/ProjectKeeperMojoIT.java | 34 ++++++++++---
.../exasol/projectkeeper/ProjectKeeper.java | 3 +-
.../dependencyupdate/DependencyUpdater.java | 18 +++----
.../ProjectVersionIncrementor.java | 51 ++++++++++++++-----
.../JavaProjectCrawlerRunnerIT.java | 28 ++++++++--
6 files changed, 113 insertions(+), 35 deletions(-)
diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java
index 9b5b8205..11953af5 100644
--- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java
+++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java
@@ -6,6 +6,7 @@
import org.apache.maven.model.*;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
public class MvnProjectWithProjectKeeperPluginWriter {
public static final String PROJECT_ARTIFACT_ID = "my-test-project";
@@ -42,6 +43,19 @@ public MvnProjectWithProjectKeeperPluginWriter addDependency(final String groupI
return this;
}
+ public MvnProjectWithProjectKeeperPluginWriter setArtifactFinalName(final String finalName) {
+ final Plugin plugin = new Plugin();
+ plugin.setGroupId("org.apache.maven.plugins");
+ plugin.setArtifactId("maven-assembly-plugin");
+ final Xpp3Dom configuration = new Xpp3Dom("configuration");
+ final Xpp3Dom finalNameElement = new Xpp3Dom("finalName");
+ finalNameElement.setValue(finalName);
+ configuration.addChild(finalNameElement);
+ plugin.setConfiguration(configuration);
+ this.model.getBuild().addPlugin(plugin);
+ return this;
+ }
+
private void addProjectKeeperPlugin(final String version) {
final Plugin projectKeeperPlugin = new Plugin();
projectKeeperPlugin.setGroupId("com.exasol");
diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java
index 66afb394..c80ba521 100644
--- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java
+++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java
@@ -23,6 +23,7 @@
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
+import org.hamcrest.Matcher;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
@@ -50,8 +51,9 @@ void beforeEach(final TestInfo test) throws IOException, GitAPIException {
Git.init().setDirectory(this.projectDir.toFile()).call().close();
new MvnProjectWithProjectKeeperPluginWriter(CURRENT_VERSION) //
.addDependency("org.slf4j", "slf4j-api", ORIGINAL_SLF4J_VERSION) //
+ .setArtifactFinalName("dummy-${project.version}") //
.writeAsPomToProject(this.projectDir);
- LOG.info(() -> "Running test " + test.getDisplayName() + "...");
+ LOG.info(() -> "Running test " + test.getDisplayName() + " using project " + this.projectDir + "...");
verifier = mavenIntegrationTestEnvironment.getVerifier(this.projectDir);
}
@@ -89,15 +91,19 @@ void testJacocoAgentIsExtracted() throws VerificationException, IOException {
" - udf_coverage\n");
verifier.executeGoal("project-keeper:fix");
verifier.executeGoal("package");
- assertThat(this.projectDir.resolve(Path.of("target", "jacoco-agent", "org.jacoco.agent-runtime.jar")).toFile(),
- anExistingFile());
+ assertThat(projectDir.resolve("target/jacoco-agent/org.jacoco.agent-runtime.jar").toFile(), anExistingFile());
}
@Test
void testUpgradeDependencies() throws VerificationException, IOException {
writeProjectKeeperConfig("sources:\n" + //
" - type: maven\n" + //
- " path: pom.xml\n");
+ " path: pom.xml\n" + //
+ " modules:\n" + //
+ " - jar_artifact\n");
+ final Path userGuidePath = projectDir.resolve("user_guide.md");
+ writeFile(userGuidePath, "artifact reference: dummy-0.1.0.jar");
+
verifier.executeGoal("project-keeper:fix");
assertThat("original version", readPom().getVersion(), equalTo("0.1.0"));
@@ -113,8 +119,10 @@ void testUpgradeDependencies() throws VerificationException, IOException {
final String updatedSlf4jVersion = updatedPom.getDependencies().get(0).getVersion();
assertThat("updated SLF4J version", updatedSlf4jVersion,
allOf(not(equalTo(ORIGINAL_SLF4J_VERSION)), not(startsWith("1.")), startsWith("2.")));
- final String changesContent = Files.readString(projectDir.resolve(ChangesFile.getPathForVersion(newVersion)));
- assertThat(changesContent, allOf(startsWith("blah")));
+ assertContent(userGuidePath, equalTo("artifact reference: dummy-0.1.1.jar\n"));
+ assertContent(ChangesFile.getPathForVersion(newVersion),
+ allOf(startsWith("# My Test Project 0.1.1, released 2024-??-??"),
+ containsString("* Added `org.slf4j:slf4j-api:")));
}
private void updateReleaseDate(final String changeLogVersion, final String newReleaseDate) {
@@ -150,6 +158,18 @@ void testSkip(final String phase) throws IOException, VerificationException {
}
private void writeProjectKeeperConfig(final String content) throws IOException {
- Files.writeString(this.projectDir.resolve(".project-keeper.yml"), content);
+ writeFile(this.projectDir.resolve(".project-keeper.yml"), content);
+ }
+
+ private void writeFile(final Path path, final String content) throws IOException {
+ Files.writeString(path, content);
+ }
+
+ private void assertContent(Path path, final Matcher contentMatcher) throws IOException {
+ if (!path.isAbsolute()) {
+ path = projectDir.resolve(path);
+ }
+ final String changesContent = Files.readString(path);
+ assertThat(changesContent, contentMatcher);
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java
index 1e457768..6f9f1cdd 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/ProjectKeeper.java
@@ -314,6 +314,7 @@ private Provision getValidationProvision() {
*/
public boolean updateDependencies() {
final Provision provision = getValidationProvision();
- return DependencyUpdater.create(this, logger, projectDir, provision.projectVersion()).updateDependencies();
+ return DependencyUpdater.create(this, config, logger, projectDir, provision.projectVersion())
+ .updateDependencies();
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
index 293a7475..7c6d2940 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
@@ -2,14 +2,12 @@
import java.nio.file.Path;
import java.time.Duration;
-import java.time.Instant;
-import java.util.List;
import com.exasol.errorreporting.ExaError;
import com.exasol.projectkeeper.Logger;
import com.exasol.projectkeeper.ProjectKeeper;
+import com.exasol.projectkeeper.shared.config.ProjectKeeperConfig;
import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder;
-import com.exasol.projectkeeper.sources.analyze.generic.SimpleProcess;
/**
* This class runs the dependency update process.
@@ -34,15 +32,16 @@ public class DependencyUpdater {
* Create a new instance.
*
* @param projectKeeper project keeper reference
+ * @param config
* @param logger the logger to which we should write log messages
* @param projectDir the project directory
* @param currentProjectVersion the project's current version
* @return a new dependency updater
*/
- public static DependencyUpdater create(final ProjectKeeper projectKeeper, final Logger logger,
- final Path projectDir, final String currentProjectVersion) {
+ public static DependencyUpdater create(final ProjectKeeper projectKeeper, ProjectKeeperConfig config,
+ final Logger logger, final Path projectDir, final String currentProjectVersion) {
return new DependencyUpdater(projectKeeper, logger, projectDir,
- new ProjectVersionIncrementor(logger, projectDir, currentProjectVersion));
+ new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion));
}
/**
@@ -79,11 +78,8 @@ private void updateDependencyVersions() {
}
private void runMaven(final String mavenGoal) {
- final List command = MavenProcessBuilder.create().addArgument("--batch-mode").addArgument(mavenGoal)
- .build();
- final Instant start = Instant.now();
- SimpleProcess.start(projectDir, command).waitUntilFinished(MAVEN_COMMAND_TIMEOUT);
- logger.info("Running maven goal " + mavenGoal + " took " + Duration.between(start, Instant.now()));
+ MavenProcessBuilder.create().addArgument(mavenGoal).workingDir(projectDir).startSimpleProcess()
+ .waitUntilFinished(MAVEN_COMMAND_TIMEOUT);
}
private void runProjectKeeperFix() {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
index 7a07464a..27d0209a 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
@@ -1,5 +1,7 @@
package com.exasol.projectkeeper.dependencyupdate;
+import static com.exasol.projectkeeper.shared.config.ProjectKeeperModule.JAR_ARTIFACT;
+
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
@@ -15,24 +17,29 @@
import com.exasol.errorreporting.ExaError;
import com.exasol.projectkeeper.Logger;
+import com.exasol.projectkeeper.shared.config.ProjectKeeperConfig;
+import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder;
import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO;
import com.vdurmont.semver4j.Semver;
class ProjectVersionIncrementor {
private static final ZoneId UTC_ZONE = ZoneId.of("UTC");
+ private final ProjectKeeperConfig config;
private final String currentProjectVersion;
private final ChangesFileIO changesFileIO;
private final Clock clock;
private final Path projectDir;
private final Logger logger;
- ProjectVersionIncrementor(final Logger logger, final Path projectDir, final String currentProjectVersion) {
- this(logger, projectDir, currentProjectVersion, new ChangesFileIO(), Clock.systemUTC());
+ ProjectVersionIncrementor(final ProjectKeeperConfig config, final Logger logger, final Path projectDir,
+ final String currentProjectVersion) {
+ this(config, logger, projectDir, currentProjectVersion, new ChangesFileIO(), Clock.systemUTC());
}
- ProjectVersionIncrementor(final Logger logger, final Path projectDir, final String currentProjectVersion,
- final ChangesFileIO changesFileIO, final Clock clock) {
+ ProjectVersionIncrementor(final ProjectKeeperConfig config, final Logger logger, final Path projectDir,
+ final String currentProjectVersion, final ChangesFileIO changesFileIO, final Clock clock) {
+ this.config = config;
this.logger = logger;
this.projectDir = projectDir;
this.changesFileIO = changesFileIO;
@@ -68,17 +75,35 @@ private LocalDate today() {
}
void incrementProjectVersion() {
- final Path path = getPomPath();
- final Model pom = readPom(path);
+
+ final Model pom = readPom();
if (!this.currentProjectVersion.equals(pom.getVersion())) {
throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-174").message(
"Inconsistent project version {{version in pom file}} found in pom {{pom file path}}, expected {{expected version}}",
- pom.getVersion(), path, currentProjectVersion).toString());
+ pom.getVersion(), pom.getPomFile(), currentProjectVersion).ticketMitigation().toString());
}
+ incrementVersion(pom);
+ if (usesReferenceCheckerPlugin()) {
+ updateReferences();
+ }
+ }
+
+ private boolean usesReferenceCheckerPlugin() {
+ return config.getSources().stream().anyMatch(source -> source.getModules().contains(JAR_ARTIFACT));
+ }
+
+ private void updateReferences() {
+ logger.info("Unify artifact references");
+ MavenProcessBuilder.create().addArgument("artifact-reference-checker:unify").workingDir(projectDir)
+ .startSimpleProcess().waitUntilFinished(Duration.ofSeconds(30));
+ }
+
+ private void incrementVersion(final Model pom) {
final String nextVersion = getIncrementedVersion(currentProjectVersion);
- logger.info("Incrementing version from " + currentProjectVersion + " to " + nextVersion + " in POM " + path);
+ logger.info("Incrementing version from " + currentProjectVersion + " to " + nextVersion + " in POM "
+ + pom.getPomFile());
pom.setVersion(nextVersion);
- writePom(path, pom);
+ writePom(pom);
}
static String getIncrementedVersion(final String version) {
@@ -86,7 +111,8 @@ static String getIncrementedVersion(final String version) {
return current.nextPatch().toString();
}
- private Model readPom(final Path path) {
+ private Model readPom() {
+ final Path path = getPomPath();
try {
return new MavenXpp3Reader().read(Files.newBufferedReader(path));
} catch (IOException | XmlPullParserException exception) {
@@ -95,9 +121,10 @@ private Model readPom(final Path path) {
}
}
- private void writePom(final Path path, final Model pom) {
+ private void writePom(final Model pom) {
+ final Path path = getPomPath();
try {
- new MavenXpp3Writer().write(Files.newOutputStream(getPomPath()), pom);
+ new MavenXpp3Writer().write(Files.newOutputStream(path), pom);
} catch (final IOException exception) {
throw new UncheckedIOException(ExaError.messageBuilder("E-PK-CORE-173")
.message("Failed to write pom {{pom file path}}", path).toString(), exception);
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
index 0d378c26..56619d8b 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
@@ -2,8 +2,9 @@
import static com.exasol.projectkeeper.shared.dependencies.BaseDependency.Type.COMPILE;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.FileWriter;
import java.io.IOException;
@@ -44,8 +45,7 @@ void testGetDependencyChanges(@TempDir final Path tempDir) throws GitAPIExceptio
Git.init().setDirectory(tempDir.toFile()).call().close();
final Path pomFile = tempDir.resolve("pom.xml");
writePomFile(pomFile);
- final MavenProjectCrawlResult result = new JavaProjectCrawlerRunner(testMavenRepo,
- TestEnvBuilder.CURRENT_VERSION).crawlProject(pomFile);
+ final MavenProjectCrawlResult result = crawlProject(pomFile);
final CrawledMavenProject mavenProject = result.getCrawledProjects()
.get(pomFile.toAbsolutePath().toString().replace("\\", "/"));
final ProjectDependency expectedDependency = ProjectDependency.builder() //
@@ -63,6 +63,26 @@ void testGetDependencyChanges(@TempDir final Path tempDir) throws GitAPIExceptio
);
}
+ MavenProjectCrawlResult crawlProject(final Path... pomFiles) {
+ return new JavaProjectCrawlerRunner(testMavenRepo, TestEnvBuilder.CURRENT_VERSION).crawlProject(pomFiles);
+ }
+
+ @Test
+ void testGetDependencyChangesFailsForEmptyPomList() throws GitAPIException, IOException {
+ final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> crawlProject());
+ assertThat(exception.getMessage(), containsString(
+ "E-PK-MPC-64: Property 'projectsToCrawl' is not defined or empty. Specify property with least one pom file."));
+ }
+
+ @Test
+ void testGetDependencyChangesFailsForMissingPom() throws GitAPIException, IOException {
+ final Path missingPomFile = Path.of("missing-pom-file");
+ final IllegalStateException exception = assertThrows(IllegalStateException.class,
+ () -> this.crawlProject(missingPomFile));
+ assertThat(exception.getMessage(), allOf(containsString("[FATAL] Non-readable POM"),
+ containsString(missingPomFile + " (No such file or directory)")));
+ }
+
private void writePomFile(final Path pomFile) throws IOException {
final TestMavenModel model = new TestMavenModel();
model.addDependency(DEPENDENCY_ID, DEPENDENCY_GROUP, "", DEPENDENCY_VERSION);
@@ -70,4 +90,4 @@ private void writePomFile(final Path pomFile) throws IOException {
new MavenXpp3Writer().write(fileWriter, model);
}
}
-}
\ No newline at end of file
+}
From 5f6cd41dde9da9b61e298df1d3e455b38d590efc Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 31 Jan 2024 15:38:48 +0100
Subject: [PATCH 46/78] Fix error message
---
.../projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java
index 3af17dca..9bef4677 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java
@@ -30,7 +30,7 @@ void analyzingSourcesWithInvalidOwnVersionFails() {
final IllegalStateException exception = assertThrows(IllegalStateException.class,
() -> analyze(OWN_VERSION, mavenSources));
assertThat(exception.getMessage(),
- allOf(containsString("E-PK-CORE-78: Failed to run command"),
+ allOf(containsString("E-PK-CORE-126: Failed to run command"),
containsString("[ERROR] Plugin com.exasol:project-keeper-java-project-crawler:" + OWN_VERSION
+ " or one of its dependencies could not be resolved")));
}
From 5e30b367d531454e4e6bec34af5b869db375a4f3 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 31 Jan 2024 15:42:12 +0100
Subject: [PATCH 47/78] Fix javadoc
---
.../projectkeeper/dependencyupdate/DependencyUpdater.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
index 7c6d2940..72345744 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
@@ -32,13 +32,13 @@ public class DependencyUpdater {
* Create a new instance.
*
* @param projectKeeper project keeper reference
- * @param config
+ * @param config project keeper configuration
* @param logger the logger to which we should write log messages
* @param projectDir the project directory
* @param currentProjectVersion the project's current version
* @return a new dependency updater
*/
- public static DependencyUpdater create(final ProjectKeeper projectKeeper, ProjectKeeperConfig config,
+ public static DependencyUpdater create(final ProjectKeeper projectKeeper, final ProjectKeeperConfig config,
final Logger logger, final Path projectDir, final String currentProjectVersion) {
return new DependencyUpdater(projectKeeper, logger, projectDir,
new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion));
From eff0e2911f4ce0be6687aa75aaf469698a8fb06c Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 31 Jan 2024 15:56:23 +0100
Subject: [PATCH 48/78] Use \n as line separator for changes file
---
.../projectkeeper/validators/changesfile/ChangesFileIO.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java
index 07aa3acd..6045a3a6 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java
@@ -19,8 +19,7 @@ public class ChangesFileIO {
private static final String DATE_PATTERN = "\\d{4}-[\\d?]{2}-[\\d?]{2}";
private static final Pattern FIRST_LINE_PATTERN = Pattern
.compile("^# (" + PROJECT_NAME_PATTERN + ") (" + VERSION_PATTERN + "), released (" + DATE_PATTERN + ")$");
- private static final Pattern SECTION_HEADING_PATTERN = Pattern.compile("\\s*##\\s.*");
- private static final String LINE_SEPARATOR = System.lineSeparator();
+ private static final String LINE_SEPARATOR = "\n";
/**
* Read a {@link ChangesFile} from disk.
From f262f4e9659d23633bc5a10701744262c09e2f3f Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 31 Jan 2024 16:02:15 +0100
Subject: [PATCH 49/78] Copy codename when fixing changes file
---
.../validators/changesfile/ChangesFile.java | 12 ++++++------
.../validators/changesfile/ChangesFileTest.java | 5 ++++-
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
index d95e836e..d2d54039 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
@@ -25,12 +25,12 @@ public final class ChangesFile {
private final ChangesFileSection dependencyChangeSection;
private ChangesFile(final Builder builder) {
- this.projectName = Objects.requireNonNull(builder.projectName, "missing projectName");
- this.projectVersion = Objects.requireNonNull(builder.projectVersion, "missing projectVersion");
- this.releaseDate = Objects.requireNonNull(builder.releaseDate, "missing releaseDate");
+ this.projectName = builder.projectName;
+ this.projectVersion = builder.projectVersion;
+ this.releaseDate = builder.releaseDate;
this.codeName = builder.codeName;
this.summarySection = builder.summarySection;
- this.sections = List.copyOf(Objects.requireNonNull(builder.sections, "missing sections"));
+ this.sections = List.copyOf(builder.sections);
this.dependencyChangeSection = builder.dependencyChangeSection;
}
@@ -61,8 +61,8 @@ public static Builder builder() {
*/
public Builder toBuilder() {
return builder().projectName(this.projectName).projectVersion(this.projectVersion.toString())
- .releaseDate(this.releaseDate).summary(this.summarySection).sections(List.copyOf(this.sections))
- .dependencyChangeSection(this.dependencyChangeSection);
+ .releaseDate(this.releaseDate).codeName(this.codeName).summary(this.summarySection)
+ .sections(List.copyOf(this.sections)).dependencyChangeSection(this.dependencyChangeSection);
}
/**
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java
index 86701f2f..d4b3ab20 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java
@@ -41,7 +41,10 @@ void toBuilderCreatesCopy() {
private Builder builder() {
return ChangesFile.builder().projectName("name").projectVersion("1.2.3").releaseDate("2023-??-??")
- .summary(ChangesFileSection.builder("## Summary").build())
+ .codeName("my code name")
+ .summary(ChangesFileSection.builder("## Summary").addLine("summary content").build())
+ .dependencyChangeSection(ChangesFileSection.builder("## Dependency Updates")
+ .addLine("dependency update content").build())
.addSection(ChangesFileSection.builder("section 1").build());
}
From 562db8c090ea57b2af56fa44cb15414ff8d6922e Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 31 Jan 2024 16:24:32 +0100
Subject: [PATCH 50/78] Fix failing tests
---
.../projectkeeper/validators/changesfile/ChangesFile.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
index d2d54039..b6e1020b 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
@@ -230,7 +230,7 @@ public Builder releaseDate(final String releaseDate) {
* @return self for fluent programming
*/
public Builder codeName(final String codeName) {
- this.codeName = codeName.isBlank() ? null : codeName;
+ this.codeName = codeName != null && codeName.isBlank() ? null : codeName;
return this;
}
From 7e5c1393a47d2a8f6dadef16aa2627adf726ac80 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 31 Jan 2024 16:37:13 +0100
Subject: [PATCH 51/78] Fix windows tests
---
.../projectkeeper/validators/changesfile/ChangesFileIOTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java
index 5da24627..3f7748c1 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java
@@ -133,7 +133,7 @@ private Path loadExampleFileToTempDir() throws IOException {
private String readExampleFile() throws IOException {
try (final InputStream exampleFileStream = getExampleFileStream()) {
- return new String(exampleFileStream.readAllBytes(), StandardCharsets.UTF_8);
+ return new String(exampleFileStream.readAllBytes(), StandardCharsets.UTF_8).replace("\r\n", "\n");
}
}
From ef6c30b91576b58e1469e0f60103d96ef47b8d58 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 31 Jan 2024 16:50:03 +0100
Subject: [PATCH 52/78] Adapt error message to windows
---
.../com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
index 56619d8b..ea11a2c7 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
@@ -79,8 +79,8 @@ void testGetDependencyChangesFailsForMissingPom() throws GitAPIException, IOExce
final Path missingPomFile = Path.of("missing-pom-file");
final IllegalStateException exception = assertThrows(IllegalStateException.class,
() -> this.crawlProject(missingPomFile));
- assertThat(exception.getMessage(), allOf(containsString("[FATAL] Non-readable POM"),
- containsString(missingPomFile + " (No such file or directory)")));
+ assertThat(exception.getMessage(),
+ allOf(containsString("[FATAL] Non-readable POM"), containsString(missingPomFile.toString())));
}
private void writePomFile(final Path pomFile) throws IOException {
From a69afaf6ad0dff7e82be9f029e76dbd62791d912 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 1 Feb 2024 07:46:02 +0100
Subject: [PATCH 53/78] Fix integration test for windows
---
.../plugin/ProjectKeeperMojoIT.java | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java
index c80ba521..c7ea6a74 100644
--- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java
+++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java
@@ -115,14 +115,14 @@ void testUpgradeDependencies() throws VerificationException, IOException {
final Model updatedPom = readPom();
final String newVersion = "0.1.1";
- assertThat("incremented version", updatedPom.getVersion(), equalTo(newVersion));
final String updatedSlf4jVersion = updatedPom.getDependencies().get(0).getVersion();
- assertThat("updated SLF4J version", updatedSlf4jVersion,
- allOf(not(equalTo(ORIGINAL_SLF4J_VERSION)), not(startsWith("1.")), startsWith("2.")));
- assertContent(userGuidePath, equalTo("artifact reference: dummy-0.1.1.jar\n"));
- assertContent(ChangesFile.getPathForVersion(newVersion),
- allOf(startsWith("# My Test Project 0.1.1, released 2024-??-??"),
- containsString("* Added `org.slf4j:slf4j-api:")));
+ assertAll(() -> assertThat("incremented version", updatedPom.getVersion(), equalTo(newVersion)),
+ () -> assertThat("updated SLF4J version", updatedSlf4jVersion,
+ allOf(not(equalTo(ORIGINAL_SLF4J_VERSION)), not(startsWith("1.")), startsWith("2."))),
+ () -> assertContent(userGuidePath, startsWith("artifact reference: dummy-0.1.1.jar")),
+ () -> assertContent(ChangesFile.getPathForVersion(newVersion),
+ allOf(startsWith("# My Test Project 0.1.1, released 2024-??-??"),
+ containsString("* Added `org.slf4j:slf4j-api:"))));
}
private void updateReleaseDate(final String changeLogVersion, final String newReleaseDate) {
@@ -170,6 +170,6 @@ private void assertContent(Path path, final Matcher contentMatcher) thro
path = projectDir.resolve(path);
}
final String changesContent = Files.readString(path);
- assertThat(changesContent, contentMatcher);
+ assertThat("content of file " + path, changesContent, contentMatcher);
}
}
From 56ad0d2265602e1f9e08d9dbef6659e962a7dd40 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 1 Feb 2024 07:53:08 +0100
Subject: [PATCH 54/78] Remove unused code
---
.../sources/analyze/generic/MavenProcessBuilder.java | 5 -----
1 file changed, 5 deletions(-)
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
index cfbf386b..56a0cf28 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
@@ -3,10 +3,8 @@
import static java.util.Arrays.asList;
import java.nio.file.Path;
-import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
-import java.util.logging.Logger;
import com.exasol.projectkeeper.OsCheck;
import com.exasol.projectkeeper.OsCheck.OSType;
@@ -15,9 +13,6 @@
* This class allows building and starting a {@code mvn} command.
*/
public class MavenProcessBuilder {
-
- private static final Logger LOG = Logger.getLogger(MavenProcessBuilder.class.getName());
- private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(30);
private final List command = new ArrayList<>();
private Path workingDir = null;
From 912573b56f313f0c7927747191e78ee19a50c6c5 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 1 Feb 2024 16:08:45 +0100
Subject: [PATCH 55/78] Dependency upgrade process Fixes #515
---
parent-pom/pom.xml | 6 ++++
.../dependencyupdate/ChangesFileUpdater.java | 16 +++++++++
.../dependencyupdate/DependencyUpdater.java | 36 ++++++++++++++-----
.../ProjectVersionIncrementor.java | 9 ++---
4 files changed, 54 insertions(+), 13 deletions(-)
create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java
diff --git a/parent-pom/pom.xml b/parent-pom/pom.xml
index 6993b74f..c61362f7 100644
--- a/parent-pom/pom.xml
+++ b/parent-pom/pom.xml
@@ -214,6 +214,12 @@
1.4.8test
+
+ org.itsallcode
+ hamcrest-auto-matcher
+ 0.6.0
+ test
+
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java
new file mode 100644
index 00000000..e8c2667e
--- /dev/null
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java
@@ -0,0 +1,16 @@
+package com.exasol.projectkeeper.dependencyupdate;
+
+import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder;
+
+class ChangesFileUpdater {
+ ChangesFile update(final ChangesFile changesFile) {
+ final Builder builder = changesFile.toBuilder();
+ update(builder);
+ return builder.build();
+ }
+
+ private void update(final Builder builder) {
+
+ }
+}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
index 72345744..aec19dd7 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
@@ -8,6 +8,8 @@
import com.exasol.projectkeeper.ProjectKeeper;
import com.exasol.projectkeeper.shared.config.ProjectKeeperConfig;
import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO;
/**
* This class runs the dependency update process.
@@ -19,13 +21,20 @@ public class DependencyUpdater {
private final Logger logger;
private final Path projectDir;
private final ProjectVersionIncrementor projectVersionIncrementor;
+ private final ChangesFileIO changesFileIO;
+ private final String currentProjectVersion;
+ private final ChangesFileUpdater changesFileUpdater;
DependencyUpdater(final ProjectKeeper projectKeeper, final Logger logger, final Path projectDir,
- final ProjectVersionIncrementor projectVersionIncrementor) {
+ final String currentProjectVersion, final ProjectVersionIncrementor projectVersionIncrementor,
+ final ChangesFileIO changesFileIO, final ChangesFileUpdater changesFileUpdater) {
this.projectKeeper = projectKeeper;
this.logger = logger;
this.projectDir = projectDir;
+ this.currentProjectVersion = currentProjectVersion;
this.projectVersionIncrementor = projectVersionIncrementor;
+ this.changesFileIO = changesFileIO;
+ this.changesFileUpdater = changesFileUpdater;
}
/**
@@ -40,8 +49,9 @@ public class DependencyUpdater {
*/
public static DependencyUpdater create(final ProjectKeeper projectKeeper, final ProjectKeeperConfig config,
final Logger logger, final Path projectDir, final String currentProjectVersion) {
- return new DependencyUpdater(projectKeeper, logger, projectDir,
- new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion));
+ return new DependencyUpdater(projectKeeper, logger, projectDir, currentProjectVersion,
+ new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion), new ChangesFileIO(),
+ new ChangesFileUpdater());
}
/**
@@ -56,19 +66,20 @@ public static DependencyUpdater create(final ProjectKeeper projectKeeper, final
* @return {@code true} if the process succeeded.
*/
public boolean updateDependencies() {
- incrementProjectVersion();
+ final String version = incrementProjectVersion();
updateDependencyVersions();
runProjectKeeperFix();
- updateChangelog();
+ updateChangelog(version);
return true;
}
- private void incrementProjectVersion() {
+ private String incrementProjectVersion() {
if (projectVersionIncrementor.isCurrentVersionReleased()) {
logger.info("Current version was already released: increment version");
- projectVersionIncrementor.incrementProjectVersion();
+ return projectVersionIncrementor.incrementProjectVersion();
} else {
logger.info("Current version was not yet released: no need to increment");
+ return currentProjectVersion;
}
}
@@ -91,7 +102,14 @@ private void runProjectKeeperFix() {
}
}
- private void updateChangelog() {
- // TODO Auto-generated method stub
+ private void updateChangelog(final String version) {
+ final Path changesFilePath = getChangesFilePath(version);
+ final ChangesFile changesFile = changesFileIO.read(changesFilePath);
+ final ChangesFile updatedChanges = changesFileUpdater.update(changesFile);
+ changesFileIO.write(updatedChanges, changesFilePath);
+ }
+
+ private Path getChangesFilePath(final String version) {
+ return projectDir.resolve(ChangesFile.getPathForVersion(version));
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
index 27d0209a..95f2f383 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
@@ -74,18 +74,18 @@ private LocalDate today() {
return LocalDate.ofInstant(clock.instant(), UTC_ZONE);
}
- void incrementProjectVersion() {
-
+ String incrementProjectVersion() {
final Model pom = readPom();
if (!this.currentProjectVersion.equals(pom.getVersion())) {
throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-174").message(
"Inconsistent project version {{version in pom file}} found in pom {{pom file path}}, expected {{expected version}}",
pom.getVersion(), pom.getPomFile(), currentProjectVersion).ticketMitigation().toString());
}
- incrementVersion(pom);
+ final String nextVersion = incrementVersion(pom);
if (usesReferenceCheckerPlugin()) {
updateReferences();
}
+ return nextVersion;
}
private boolean usesReferenceCheckerPlugin() {
@@ -98,12 +98,13 @@ private void updateReferences() {
.startSimpleProcess().waitUntilFinished(Duration.ofSeconds(30));
}
- private void incrementVersion(final Model pom) {
+ private String incrementVersion(final Model pom) {
final String nextVersion = getIncrementedVersion(currentProjectVersion);
logger.info("Incrementing version from " + currentProjectVersion + " to " + nextVersion + " in POM "
+ pom.getPomFile());
pom.setVersion(nextVersion);
writePom(pom);
+ return nextVersion;
}
static String getIncrementedVersion(final String version) {
From 9f86d24b414b9ce0364d6f4584dd7798503573d5 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 1 Feb 2024 16:51:05 +0100
Subject: [PATCH 56/78] Increase timeout
---
.../sources/analyze/generic/SimpleProcessIT.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java
index 9a8c7b81..1c9828cc 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java
@@ -11,11 +11,11 @@
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;
-// Windows has problems with the timeout of 10ms. Running these tests under Unix is enough.
+// Windows has problems with the timeout of 20ms. Running these tests under Unix is enough.
@DisabledOnOs(OS.WINDOWS)
class SimpleProcessIT {
- private static final Duration TIMEOUT = Duration.ofMillis(10);
+ private static final Duration TIMEOUT = Duration.ofMillis(20);
@Test
void outputStream() {
@@ -60,7 +60,7 @@ void processTimeout() {
final IllegalStateException exception = assertThrows(IllegalStateException.class,
() -> process.waitUntilFinished(TIMEOUT));
assertThat(exception.getMessage(), equalTo(
- "E-PK-CORE-128: Timeout while waiting 10ms for command 'bash -c echo output && >&2 echo error && sleep 1'. Output was 'output'\n"
+ "E-PK-CORE-128: Timeout while waiting 20ms for command 'bash -c echo output && >&2 echo error && sleep 1'. Output was 'output'\n"
+ "Error output: 'error'"));
}
From b3c51f185685f96d4dfe536fcb111d2a5b2cce18 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 7 Feb 2024 10:44:53 +0100
Subject: [PATCH 57/78] Remove duplicate files
---
.../dependencies_update_process.plantuml | 53 -------------------
doc/images/dependencies_update_process.svg | 1 -
doc/images/release_process.plantuml | 51 ------------------
doc/images/release_process.svg | 1 -
4 files changed, 106 deletions(-)
delete mode 100644 doc/images/dependencies_update_process.plantuml
delete mode 100644 doc/images/dependencies_update_process.svg
delete mode 100644 doc/images/release_process.plantuml
delete mode 100644 doc/images/release_process.svg
diff --git a/doc/images/dependencies_update_process.plantuml b/doc/images/dependencies_update_process.plantuml
deleted file mode 100644
index 5de174ae..00000000
--- a/doc/images/dependencies_update_process.plantuml
+++ /dev/null
@@ -1,53 +0,0 @@
-@startuml dependencies_update_process
-
-start
-:**dependencies_check.yml** workflow
-(triggered daily);
-note right
- Pass information about created
- issues & vulnerabilities to
- **dependencies_update.yml**
-end note
-if(Vulnerable dependencies found?) then (yes)
- group **dependencies_update.yml** workflow
- note right
- GitHub Workflow
- generated by PK
- end note
- :Run PK **update-dependencies** as Maven plugin;
- group PK **update-dependencies**
- note right
- Implement
- in PK
- end note
- if(Latest version already released?) then (yes)
- :Increment project version;
- else (no)
- endif
- :Update dependencies;
- :Run PK fix;
- note right
- Add dependency changes to
- changelog, Update list of
- dependencies, ...
- end note
- :Update changlog: add fixed vulnerabilites;
- if(pom.xml contains artifact-reference-checker-maven-plugin) then (yes)
- :Run artifact-reference-checker-maven-plugin:fix;
- else (no)
- endif
- end group
- :Create branch, commit, push &
- create pull request;
- note right
- Needs information about
- issues & vulnerabilities
- end note
- :Send Slack notification
- for success and failure;
- end group
-else (no)
- stop
-endif
-stop
-@enduml
diff --git a/doc/images/dependencies_update_process.svg b/doc/images/dependencies_update_process.svg
deleted file mode 100644
index 8fe162b6..00000000
--- a/doc/images/dependencies_update_process.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/doc/images/release_process.plantuml b/doc/images/release_process.plantuml
deleted file mode 100644
index 6f54aa41..00000000
--- a/doc/images/release_process.plantuml
+++ /dev/null
@@ -1,51 +0,0 @@
-@startuml release_process
-
-start
-note right
- Triggered manually or
- on pushes to main branch.
-end note
-group **release.yml** workflow
- note right
- Generated
- by PK
- end note
- :Run PK **verify-release** as Maven plugin;
- group PK **verify-release**
- note right
- Implemented
- in PK
- end note
- if(Release date up-to-date?\n(allow skipping the release)) then (up-to-date)
- :Run PK **verify**;
- :Run additional release checks;
- :Write changelog content to file;
- note right
- Required for creating
- the GitHub release
- end note
- else (invalid/outdated)
- :Fail build;
- stop
- endif
- end group
- :Run **mvn verify**;
- if(Maven Central deployment required) then (required)
- :Run **mvn deploy**;
- endif
- :Calculate checksums for release artifacts;
- :Create GitHub release;
- note right
- Reads changelog
- content from file
- end note
- :Attach release artifacts and
- checksums to GitHub release;
- note right
- Customizable
- end note
- :Send Slack notification
- for success & failure;
-end group
-stop
-@enduml
diff --git a/doc/images/release_process.svg b/doc/images/release_process.svg
deleted file mode 100644
index 850f6913..00000000
--- a/doc/images/release_process.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
From db954a637b10dedd9ba47744d656e67f9e4bf41a Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 7 Feb 2024 11:51:44 +0100
Subject: [PATCH 58/78] Upgrade dependencies
---
.vscode/settings.json | 3 +-
dependencies.md | 20 ++++----
doc/changes/changes_4.0.0.md | 10 ++++
maven-project-crawler/pk_generated_parent.pom | 11 +++++
parent-pom/error_code_config.yml | 8 ++++
parent-pom/pom.xml | 47 +++++++++++++++++--
pom.xml | 1 +
project-keeper-cli/pk_generated_parent.pom | 11 +++++
project-keeper-cli/pom.xml | 11 +++++
.../pk_generated_parent.pom | 11 +++++
project-keeper-maven-plugin/pom.xml | 11 +++++
project-keeper/pk_generated_parent.pom | 11 +++++
project-keeper/pom.xml | 11 +++++
.../maven_templates/versions-maven-plugin.xml | 11 +++++
shared-model-classes/pk_generated_parent.pom | 11 +++++
shared-model-classes/pom.xml | 15 ++++++
shared-test-setup/pk_generated_parent.pom | 11 +++++
shared-test-setup/pom.xml | 15 ++++++
18 files changed, 215 insertions(+), 14 deletions(-)
create mode 100644 parent-pom/error_code_config.yml
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 4f1536d8..e5310098 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -10,7 +10,8 @@
"java.sources.organizeImports.staticStarThreshold": 3,
"java.test.config": {
"vmArgs": [
- "-Djava.util.logging.config.file=src/test/resources/logging.properties"
+ "-Djava.util.logging.config.file=src/test/resources/logging.properties",
+ "-Dcom.exasol.projectkeeper.ownVersion=4.0.0"
]
},
"sonarlint.connectedMode.project": {
diff --git a/dependencies.md b/dependencies.md
index fcd2d32f..c623cd8e 100644
--- a/dependencies.md
+++ b/dependencies.md
@@ -90,6 +90,7 @@
| ------------------------------------------------------- | --------------------------------- |
| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] |
| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] |
+| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] |
| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] |
| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] |
| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] |
@@ -102,11 +103,10 @@
| [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] |
| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] |
| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] |
-| [Maven Failsafe Plugin][56] | [Apache-2.0][16] |
+| [Maven Failsafe Plugin][57] | [Apache-2.0][16] |
| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] |
| [error-code-crawler-maven-plugin][42] | [MIT License][43] |
| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] |
-| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][16] |
## Project Keeper Command Line Interface
@@ -148,14 +148,14 @@
| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] |
| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] |
| [Apache Maven Assembly Plugin][58] | [Apache-2.0][16] |
-| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][16] |
+| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] |
| [Artifact reference checker and unifier][59] | [MIT License][60] |
| [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] |
| [Apache Maven GPG Plugin][35] | [Apache-2.0][16] |
| [Apache Maven Source Plugin][36] | [Apache License, Version 2.0][16] |
| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] |
| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] |
-| [Maven Failsafe Plugin][56] | [Apache-2.0][16] |
+| [Maven Failsafe Plugin][57] | [Apache-2.0][16] |
| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] |
| [error-code-crawler-maven-plugin][42] | [MIT License][43] |
| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] |
@@ -192,14 +192,14 @@
| ------------------------------------------------------- | --------------------------------- |
| [SonarQube Scanner for Maven][22] | [GNU LGPL 3][23] |
| [Apache Maven Toolchains Plugin][24] | [Apache License, Version 2.0][16] |
+| [Maven Plugin Plugin][65] | [Apache-2.0][16] |
| [Apache Maven Compiler Plugin][25] | [Apache-2.0][16] |
| [Apache Maven Enforcer Plugin][26] | [Apache-2.0][16] |
| [Maven Flatten Plugin][27] | [Apache Software Licenese][16] |
| [org.sonatype.ossindex.maven:ossindex-maven-plugin][28] | [ASL2][29] |
| [Maven Surefire Plugin][30] | [Apache-2.0][16] |
| [Versions Maven Plugin][31] | [Apache License, Version 2.0][16] |
-| [Maven Plugin Plugin][65] | [Apache-2.0][16] |
-| [Apache Maven JAR Plugin][57] | [Apache License, Version 2.0][16] |
+| [Apache Maven JAR Plugin][56] | [Apache License, Version 2.0][16] |
| [duplicate-finder-maven-plugin Maven Mojo][32] | [Apache License 2.0][33] |
| [Apache Maven Deploy Plugin][34] | [Apache-2.0][16] |
| [Apache Maven GPG Plugin][35] | [Apache-2.0][16] |
@@ -207,7 +207,7 @@
| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] |
| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] |
| [Apache Maven Dependency Plugin][66] | [Apache-2.0][16] |
-| [Maven Failsafe Plugin][56] | [Apache-2.0][16] |
+| [Maven Failsafe Plugin][57] | [Apache-2.0][16] |
| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] |
| [error-code-crawler-maven-plugin][42] | [MIT License][43] |
| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] |
@@ -261,7 +261,7 @@
| [Apache Maven Javadoc Plugin][37] | [Apache-2.0][16] |
| [Nexus Staging Maven Plugin][38] | [Eclipse Public License][39] |
| [Apache Maven Dependency Plugin][66] | [Apache-2.0][16] |
-| [Maven Failsafe Plugin][56] | [Apache-2.0][16] |
+| [Maven Failsafe Plugin][57] | [Apache-2.0][16] |
| [JaCoCo :: Maven Plugin][40] | [Eclipse Public License 2.0][41] |
| [error-code-crawler-maven-plugin][42] | [MIT License][43] |
| [Reproducible Build Maven Plugin][44] | [Apache 2.0][29] |
@@ -350,8 +350,8 @@
[53]: https://github.com/exasol/maven-project-version-getter/blob/main/LICENSE
[54]: https://github.com/exasol/maven-plugin-integration-testing/
[55]: https://github.com/exasol/maven-plugin-integration-testing/blob/main/LICENSE
-[56]: https://maven.apache.org/surefire/maven-failsafe-plugin/
-[57]: https://maven.apache.org/plugins/maven-jar-plugin/
+[56]: https://maven.apache.org/plugins/maven-jar-plugin/
+[57]: https://maven.apache.org/surefire/maven-failsafe-plugin/
[58]: https://maven.apache.org/plugins/maven-assembly-plugin/
[59]: https://github.com/exasol/artifact-reference-checker-maven-plugin/
[60]: https://github.com/exasol/artifact-reference-checker-maven-plugin/blob/main/LICENSE
diff --git a/doc/changes/changes_4.0.0.md b/doc/changes/changes_4.0.0.md
index b249b9da..bee44ffd 100644
--- a/doc/changes/changes_4.0.0.md
+++ b/doc/changes/changes_4.0.0.md
@@ -15,6 +15,8 @@ Code name: Automatic Security Updates
#### Test Dependency Updates
* Updated `nl.jqno.equalsverifier:equalsverifier:3.15.4` to `3.15.6`
+* Updated `org.junit.jupiter:junit-jupiter-engine:5.10.1` to `5.10.2`
+* Updated `org.junit.jupiter:junit-jupiter-params:5.10.1` to `5.10.2`
* Updated `org.mockito:mockito-core:5.8.0` to `5.10.0`
#### Plugin Dependency Updates
@@ -38,6 +40,8 @@ Code name: Automatic Security Updates
* Updated `com.exasol:project-keeper-shared-test-setup:3.0.1` to `4.0.0`
* Updated `nl.jqno.equalsverifier:equalsverifier:3.15.4` to `3.15.6`
+* Updated `org.junit.jupiter:junit-jupiter-engine:5.10.1` to `5.10.2`
+* Updated `org.junit.jupiter:junit-jupiter-params:5.10.1` to `5.10.2`
* Updated `org.mockito:mockito-junit-jupiter:5.8.0` to `5.10.0`
#### Plugin Dependency Updates
@@ -57,6 +61,8 @@ Code name: Automatic Security Updates
#### Test Dependency Updates
* Updated `com.exasol:project-keeper-shared-test-setup:3.0.1` to `4.0.0`
+* Updated `org.junit.jupiter:junit-jupiter-engine:5.10.1` to `5.10.2`
+* Updated `org.junit.jupiter:junit-jupiter-params:5.10.1` to `5.10.2`
#### Plugin Dependency Updates
@@ -74,6 +80,8 @@ Code name: Automatic Security Updates
#### Test Dependency Updates
+* Updated `org.junit.jupiter:junit-jupiter-engine:5.10.1` to `5.10.2`
+* Updated `org.junit.jupiter:junit-jupiter-params:5.10.1` to `5.10.2`
* Updated `org.mockito:mockito-core:5.8.0` to `5.10.0`
#### Plugin Dependency Updates
@@ -93,6 +101,8 @@ Code name: Automatic Security Updates
#### Test Dependency Updates
+* Updated `org.junit.jupiter:junit-jupiter-engine:5.10.1` to `5.10.2`
+* Updated `org.junit.jupiter:junit-jupiter-params:5.10.1` to `5.10.2`
* Updated `org.mockito:mockito-core:5.8.0` to `5.10.0`
* Updated `org.mockito:mockito-junit-jupiter:5.8.0` to `5.10.0`
diff --git a/maven-project-crawler/pk_generated_parent.pom b/maven-project-crawler/pk_generated_parent.pom
index b9745cc7..266874fa 100644
--- a/maven-project-crawler/pk_generated_parent.pom
+++ b/maven-project-crawler/pk_generated_parent.pom
@@ -189,6 +189,17 @@
file:///${project.basedir}/versionsMavenPluginRules.xml
+ false
+ true
+ true
+ true
+ false
+ true
+ true
+ true
+ false
+ true
+ true
diff --git a/parent-pom/error_code_config.yml b/parent-pom/error_code_config.yml
new file mode 100644
index 00000000..1389755e
--- /dev/null
+++ b/parent-pom/error_code_config.yml
@@ -0,0 +1,8 @@
+# This file is only used for release guide.
+# Actual error codes are based on files error_code_config.yml in individual subfolders.
+
+error-tags:
+ PK-PARENT:
+ packages:
+ - dummy
+ highest-index: 1
diff --git a/parent-pom/pom.xml b/parent-pom/pom.xml
index db5a528b..a0ee2850 100644
--- a/parent-pom/pom.xml
+++ b/parent-pom/pom.xml
@@ -5,7 +5,7 @@
project-keeper-parent-pompom${revision}
- Project Keeper parent pom
+ Project Keeper Parent POMThis tool checks and unifies a project's structure according to the Exasol integration team's
repository standards.
@@ -31,7 +31,7 @@
4.0.03.9.63.6.3
- 5.10.1
+ 5.10.22.9.15.10.0UTF-8
@@ -111,7 +111,7 @@
org.eclipse.jgitorg.eclipse.jgit
-
+
6.7.0.202309050840-r
@@ -214,6 +214,12 @@
1.4.8test
+
+ org.itsallcode
+ hamcrest-auto-matcher
+ 0.6.0
+ test
+
@@ -226,5 +232,40 @@
+
+
+ org.codehaus.mojo
+ versions-maven-plugin
+ 2.16.2
+
+
+ display-updates
+ package
+
+ display-plugin-updates
+ display-dependency-updates
+
+
+
+
+ file:///${project.basedir}/../project-keeper/versionsMavenPluginRules.xml
+ false
+ true
+ true
+ true
+ false
+ true
+ true
+ true
+ false
+
+
+ org.slf4j:slf4j-jdk14:jar:*:*
+
+ org.eclipse.jgit:org.eclipse.jgit:jar:*:6.8.0.202311291450-r
+
+
+
+
diff --git a/pom.xml b/pom.xml
index a2d83f9e..def9b3ba 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,6 +13,7 @@
shared-test-setupmaven-project-crawlerproject-keeper-maven-plugin
+ parent-pomProject Keeper Root Project
diff --git a/project-keeper-cli/pk_generated_parent.pom b/project-keeper-cli/pk_generated_parent.pom
index 2f2022b7..21714a21 100644
--- a/project-keeper-cli/pk_generated_parent.pom
+++ b/project-keeper-cli/pk_generated_parent.pom
@@ -181,6 +181,17 @@
file:///${project.basedir}/versionsMavenPluginRules.xml
+ false
+ true
+ true
+ true
+ false
+ true
+ true
+ true
+ false
+ true
+ true
diff --git a/project-keeper-cli/pom.xml b/project-keeper-cli/pom.xml
index 084c8570..bb11e9b5 100644
--- a/project-keeper-cli/pom.xml
+++ b/project-keeper-cli/pom.xml
@@ -59,6 +59,17 @@
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ -Xlint:all,-processing
+ -Werror
+
+
+ org.apache.maven.pluginsmaven-assembly-plugin
diff --git a/project-keeper-maven-plugin/pk_generated_parent.pom b/project-keeper-maven-plugin/pk_generated_parent.pom
index 7b91571e..c9739780 100644
--- a/project-keeper-maven-plugin/pk_generated_parent.pom
+++ b/project-keeper-maven-plugin/pk_generated_parent.pom
@@ -189,6 +189,17 @@
file:///${project.basedir}/versionsMavenPluginRules.xml
+ false
+ true
+ true
+ true
+ false
+ true
+ true
+ true
+ false
+ true
+ true
diff --git a/project-keeper-maven-plugin/pom.xml b/project-keeper-maven-plugin/pom.xml
index 06af4b13..f5a387f5 100644
--- a/project-keeper-maven-plugin/pom.xml
+++ b/project-keeper-maven-plugin/pom.xml
@@ -95,6 +95,17 @@
project-keeper
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ -Xlint:all,-processing
+ -Werror
+
+
+ org.apache.maven.pluginsmaven-jar-plugin
diff --git a/project-keeper/pk_generated_parent.pom b/project-keeper/pk_generated_parent.pom
index 44c2a879..35f33b92 100644
--- a/project-keeper/pk_generated_parent.pom
+++ b/project-keeper/pk_generated_parent.pom
@@ -181,6 +181,17 @@
file:///${project.basedir}/versionsMavenPluginRules.xml
+ false
+ true
+ true
+ true
+ false
+ true
+ true
+ true
+ false
+ true
+ true
diff --git a/project-keeper/pom.xml b/project-keeper/pom.xml
index 31e652b2..08f81c72 100644
--- a/project-keeper/pom.xml
+++ b/project-keeper/pom.xml
@@ -119,6 +119,17 @@
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ -Xlint:all,-processing
+ -Werror
+
+
+
diff --git a/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml b/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml
index a16896b7..d3e43388 100644
--- a/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml
+++ b/project-keeper/src/main/resources/maven_templates/versions-maven-plugin.xml
@@ -14,5 +14,16 @@
file:///${project.basedir}/versionsMavenPluginRules.xml
+ false
+ true
+ true
+ true
+ false
+ true
+ true
+ true
+ false
+ true
+ true
diff --git a/shared-model-classes/pk_generated_parent.pom b/shared-model-classes/pk_generated_parent.pom
index e5e3dba0..2bde1923 100644
--- a/shared-model-classes/pk_generated_parent.pom
+++ b/shared-model-classes/pk_generated_parent.pom
@@ -181,6 +181,17 @@
file:///${project.basedir}/versionsMavenPluginRules.xml
+ false
+ true
+ true
+ true
+ false
+ true
+ true
+ true
+ false
+ true
+ true
diff --git a/shared-model-classes/pom.xml b/shared-model-classes/pom.xml
index 6ec90efd..d9133db8 100644
--- a/shared-model-classes/pom.xml
+++ b/shared-model-classes/pom.xml
@@ -75,4 +75,19 @@
test
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ -Xlint:all,-processing
+ -Werror
+
+
+
+
+
diff --git a/shared-test-setup/pk_generated_parent.pom b/shared-test-setup/pk_generated_parent.pom
index 91f61d03..299d5f54 100644
--- a/shared-test-setup/pk_generated_parent.pom
+++ b/shared-test-setup/pk_generated_parent.pom
@@ -170,6 +170,17 @@
file:///${project.basedir}/versionsMavenPluginRules.xml
+ false
+ true
+ true
+ true
+ false
+ true
+ true
+ true
+ false
+ true
+ true
diff --git a/shared-test-setup/pom.xml b/shared-test-setup/pom.xml
index 9b492f1f..f5d81b06 100644
--- a/shared-test-setup/pom.xml
+++ b/shared-test-setup/pom.xml
@@ -34,4 +34,19 @@
maven-model
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ -Xlint:all,-processing
+ -Werror
+
+
+
+
+
From d354a61bb1aaee3d137bff71808e043639d3f803 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 7 Feb 2024 12:01:51 +0100
Subject: [PATCH 59/78] #515: Refactoring
---
maven-project-crawler/error_code_config.yml | 2 +-
.../MavenProjectCrawlerMojo.java | 5 +
.../plugin/ProjectKeeperFixMojo.java | 2 +-
.../plugin/ProjectKeeperVerifyMojo.java | 2 +-
...nProjectWithProjectKeeperPluginWriter.java | 55 +++++++---
project-keeper/error_code_config.yml | 2 +-
.../JavaProjectCrawlerRunner.java | 100 ++++++------------
.../analyze/generic/MavenProcessBuilder.java | 85 +++++++++++++++
.../validators/VersionCollector.java | 6 +-
.../files/LatestChangesFileValidator.java | 6 +-
.../JavaProjectCrawlerRunnerIT.java | 28 ++++-
.../analyze/MavenSourceAnalyzerTest.java | 2 +-
.../analyze/generic/SimpleProcessIT.java | 6 +-
.../files/LatestChangesFileValidatorTest.java | 4 +-
.../src/test/resources/changesFileExample1.md | 1 -
.../MavenProjectCrawlResult.java | 2 +
.../shared/repository/GitRepositoryTest.java | 6 +-
17 files changed, 209 insertions(+), 105 deletions(-)
create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
diff --git a/maven-project-crawler/error_code_config.yml b/maven-project-crawler/error_code_config.yml
index 867099b3..cf122110 100644
--- a/maven-project-crawler/error_code_config.yml
+++ b/maven-project-crawler/error_code_config.yml
@@ -2,4 +2,4 @@ error-tags:
PK-MPC:
packages:
- com.exasol.projectkeeper
- highest-index: 63
\ No newline at end of file
+ highest-index: 64
diff --git a/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java b/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java
index f8266227..85cc9ec6 100644
--- a/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java
+++ b/maven-project-crawler/src/main/java/com/exasol/projectkeeper/MavenProjectCrawlerMojo.java
@@ -39,6 +39,11 @@ public class MavenProjectCrawlerMojo extends AbstractMojo {
// [impl -> dsn~eclipse-prefs-java-version~1]
@Override
public void execute() {
+ if (projectsToCrawl == null || projectsToCrawl.isBlank()) {
+ throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-MPC-64")
+ .message("Property {{property name}} is not defined or empty.", PROPERTY_PROJECTS_TO_CRAWL)
+ .mitigation("Specify property with least one pom file.").toString());
+ }
final MavenProjectFromFileReader mavenProjectReader = new DefaultMavenProjectFromFileReader(
this.mavenProjectBuilder, this.session);
final MavenModelFromRepositoryReader modelFromRepositoryReader = new MavenModelFromRepositoryReader(
diff --git a/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperFixMojo.java b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperFixMojo.java
index 38fddf9a..5f310cea 100644
--- a/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperFixMojo.java
+++ b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperFixMojo.java
@@ -6,7 +6,7 @@
import com.exasol.projectkeeper.ProjectKeeper;
/**
- * Entry point for the fix goal.
+ * Entry point for the {@code fix} goal.
*
* Run using {@code mvn project-keeper:fix}
*
diff --git a/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperVerifyMojo.java b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperVerifyMojo.java
index 2524c634..e28c1875 100644
--- a/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperVerifyMojo.java
+++ b/project-keeper-maven-plugin/src/main/java/com/exasol/projectkeeper/plugin/ProjectKeeperVerifyMojo.java
@@ -7,7 +7,7 @@
import com.exasol.projectkeeper.ProjectKeeper;
/**
- * Entry point for the verify goal.
+ * Entry point for the {code verify} goal.
*
* Run using {@code mvn project-keeper:verify}
*
diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java
index 45437f20..11953af5 100644
--- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java
+++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java
@@ -1,34 +1,61 @@
package com.exasol.projectkeeper.plugin;
-import java.io.FileWriter;
-import java.io.IOException;
+import java.io.*;
import java.nio.file.Path;
import java.util.List;
import org.apache.maven.model.*;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
-public class MvnProjectWithProjectKeeperPluginWriter extends Model {
- private static final long serialVersionUID = -8757020322006895512L;
+public class MvnProjectWithProjectKeeperPluginWriter {
public static final String PROJECT_ARTIFACT_ID = "my-test-project";
public static final String PROJECT_VERSION = "0.1.0";
+ private final Model model;
public MvnProjectWithProjectKeeperPluginWriter(final String projectKeeperVersion) {
- this.setBuild(new Build());
- this.setVersion(PROJECT_VERSION);
- this.setArtifactId(PROJECT_ARTIFACT_ID);
- this.setGroupId("com.exasol");
- this.setModelVersion("4.0.0");
- this.setDescription("my project description");
+ this.model = new Model();
+ this.model.setBuild(new Build());
+ this.model.setVersion(PROJECT_VERSION);
+ this.model.setArtifactId(PROJECT_ARTIFACT_ID);
+ this.model.setGroupId("com.exasol");
+ this.model.setModelVersion("4.0.0");
+ this.model.setDescription("my project description");
addProjectKeeperPlugin(projectKeeperVersion);
}
- public void writeAsPomToProject(final Path projectDir) throws IOException {
- try (final FileWriter fileWriter = new FileWriter(projectDir.resolve("pom.xml").toFile())) {
- new MavenXpp3Writer().write(fileWriter, this);
+ public void writeAsPomToProject(final Path projectDir) {
+ final Path path = projectDir.resolve("pom.xml");
+ try (final FileWriter fileWriter = new FileWriter(path.toFile())) {
+ new MavenXpp3Writer().write(fileWriter, this.model);
+ } catch (final IOException exception) {
+ throw new UncheckedIOException("Failed writing POM to file " + path, exception);
}
}
+ public MvnProjectWithProjectKeeperPluginWriter addDependency(final String groupId, final String artifactId,
+ final String version) {
+ final Dependency dependency = new Dependency();
+ dependency.setGroupId(groupId);
+ dependency.setArtifactId(artifactId);
+ dependency.setVersion(version);
+ this.model.getDependencies().add(dependency);
+ return this;
+ }
+
+ public MvnProjectWithProjectKeeperPluginWriter setArtifactFinalName(final String finalName) {
+ final Plugin plugin = new Plugin();
+ plugin.setGroupId("org.apache.maven.plugins");
+ plugin.setArtifactId("maven-assembly-plugin");
+ final Xpp3Dom configuration = new Xpp3Dom("configuration");
+ final Xpp3Dom finalNameElement = new Xpp3Dom("finalName");
+ finalNameElement.setValue(finalName);
+ configuration.addChild(finalNameElement);
+ plugin.setConfiguration(configuration);
+ this.model.getBuild().addPlugin(plugin);
+ return this;
+ }
+
private void addProjectKeeperPlugin(final String version) {
final Plugin projectKeeperPlugin = new Plugin();
projectKeeperPlugin.setGroupId("com.exasol");
@@ -37,6 +64,6 @@ private void addProjectKeeperPlugin(final String version) {
final PluginExecution execution = new PluginExecution();
execution.setGoals(List.of("verify"));
projectKeeperPlugin.setExecutions(List.of(execution));
- this.getBuild().addPlugin(projectKeeperPlugin);
+ this.model.getBuild().addPlugin(projectKeeperPlugin);
}
}
diff --git a/project-keeper/error_code_config.yml b/project-keeper/error_code_config.yml
index e550c0e8..53d3c5ac 100644
--- a/project-keeper/error_code_config.yml
+++ b/project-keeper/error_code_config.yml
@@ -2,4 +2,4 @@ error-tags:
PK-CORE:
packages:
- com.exasol.projectkeeper
- highest-index: 170
+ highest-index: 179
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java
index 3c4449ee..18dcf1ed 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java
@@ -1,36 +1,28 @@
package com.exasol.projectkeeper;
-import java.io.IOException;
-import java.io.UncheckedIOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.time.Duration;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import java.util.Arrays;
import java.util.stream.Collectors;
-import com.exasol.errorreporting.ExaError;
-import com.exasol.projectkeeper.OsCheck.OSType;
import com.exasol.projectkeeper.shared.mavenprojectcrawler.MavenProjectCrawlResult;
import com.exasol.projectkeeper.shared.mavenprojectcrawler.ResponseCoder;
-import com.exasol.projectkeeper.stream.AsyncStreamReader;
-import com.exasol.projectkeeper.stream.CollectingConsumer;
+import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder;
+import com.exasol.projectkeeper.sources.analyze.generic.SimpleProcess;
/**
* Runs the maven plugin goal on the current repository and returns the parsed result.
*/
public class JavaProjectCrawlerRunner {
- private static final Logger LOGGER = Logger.getLogger(JavaProjectCrawlerRunner.class.getName());
- private static final Duration STREAM_READING_TIMEOUT = Duration.ofSeconds(1);
private final Path mvnRepositoryOverride;
private final String ownVersion;
/**
* Create a new instance of {@link JavaProjectCrawlerRunner}.
*
- * @param mvnRepositoryOverride maven repository override. Use {@code null} for default
+ * @param mvnRepositoryOverride Maven repository override. This is useful for running integration tests. Use
+ * {@code null} for default.
* @param ownVersion project-keeper version
*/
public JavaProjectCrawlerRunner(final Path mvnRepositoryOverride, final String ownVersion) {
@@ -50,67 +42,39 @@ public MavenProjectCrawlResult crawlProject(final Path... pomFiles) {
}
private String runCrawlerPlugin(final Path... pomFiles) {
- final String projectList = Arrays.stream(pomFiles).map(pomFile -> pomFile.toAbsolutePath().toString()
- // we use / instead of \ here as a fix for https://github.com/eclipse-ee4j/yasson/issues/540
- .replace(FileSystems.getDefault().getSeparator(), "/")).collect(Collectors.joining(";"));
- try {
- final List commandParts = new ArrayList<>(List.of(getMavenExecutable(), "--batch-mode",
- "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn",
- "com.exasol:project-keeper-java-project-crawler:" + this.ownVersion + ":" + "crawl",
- "-DprojectsToCrawl=" + projectList,
- /*
- * We need to disable the model cache here since it caches the parent poms with {revision} as
- * version and then runs into trouble since the cache is different when reading the old pom (for
- * comparing dependencies).
- */
- "-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true"));
- if (this.mvnRepositoryOverride != null) {
- commandParts.add("-Dmaven.repo.local=" + this.mvnRepositoryOverride);
- }
-
- LOGGER.fine(() -> "Executing command " + commandParts);
- final Process proc = new ProcessBuilder(commandParts).redirectErrorStream(true).start();
+ final MavenProcessBuilder builder = buildMavenCommand(pomFiles);
+ final SimpleProcess process = builder.startSimpleProcess();
+ process.waitUntilFinished(Duration.ofSeconds(90));
+ return new ResponseCoder().decodeResponse(process.getOutputStreamContent());
+ }
- final CollectingConsumer outputStreamConsumer = new AsyncStreamReader()
- .startCollectingConsumer(proc.getInputStream());
- final CollectingConsumer errorStreamConsumer = new AsyncStreamReader()
- .startCollectingConsumer(proc.getErrorStream());
+ private MavenProcessBuilder buildMavenCommand(final Path... pomFiles) {
+ final MavenProcessBuilder builder = MavenProcessBuilder.create()
+ .addArguments(
+ "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn",
+ "com.exasol:project-keeper-java-project-crawler:" + this.ownVersion + ":" + "crawl",
+ "-DprojectsToCrawl=" + getProjectList(pomFiles),
+ /*
+ * We need to disable the model cache here since it caches the parent poms with {revision} as
+ * version and then runs into trouble since the cache is different when reading the old pom (for
+ * comparing dependencies).
+ */
+ "-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true")
+ .workingDir(null);
- if (!proc.waitFor(90, TimeUnit.SECONDS)) {
- final String stdOutput = outputStreamConsumer.getCurrentContent();
- final String stdError = errorStreamConsumer.getCurrentContent();
- throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-81").message(
- "Timeout while executing command {{executed command|u}}. Output: {{std output}}, error: {{std error}}",
- commandParts, stdOutput, stdError).toString());
- }
- final int exitCode = proc.exitValue();
- final String output = outputStreamConsumer.getContent(STREAM_READING_TIMEOUT);
- if (exitCode != 0) {
- LOGGER.log(Level.SEVERE, output);
- throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-78").message(
- "Failed to run command {{executed command|u}}, exit code was {{exit code}}. Output:\n{{output}}",
- commandParts, exitCode, output).toString());
- }
- return new ResponseCoder().decodeResponse(output);
- } catch (final IOException exception) {
- throw new UncheckedIOException(getRunFailedMessage(), exception);
- } catch (final InterruptedException exception) {
- Thread.currentThread().interrupt();
- throw new IllegalStateException(getRunFailedMessage(), exception);
+ if (this.mvnRepositoryOverride != null) {
+ builder.addArgument("-Dmaven.repo.local=" + this.mvnRepositoryOverride);
}
+ return builder;
}
- private String getMavenExecutable() {
- final OSType osType = new OsCheck().getOperatingSystemType();
- if (osType == OSType.WINDOWS) {
- return "mvn.cmd";
- } else {
- return "mvn";
- }
+ private String getProjectList(final Path... pomFiles) {
+ return Arrays.stream(pomFiles).map(this::formatPath).collect(Collectors.joining(";"));
}
- private String getRunFailedMessage() {
- return ExaError.messageBuilder("E-PK-CORE-80").message("Failed to run project-keeper-java-project-crawler.")
- .toString();
+ private String formatPath(final Path pomFile) {
+ return pomFile.toAbsolutePath().toString()
+ // we use / instead of \ here as a fix for https://github.com/eclipse-ee4j/yasson/issues/540
+ .replace(FileSystems.getDefault().getSeparator(), "/");
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
new file mode 100644
index 00000000..56a0cf28
--- /dev/null
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
@@ -0,0 +1,85 @@
+package com.exasol.projectkeeper.sources.analyze.generic;
+
+import static java.util.Arrays.asList;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.exasol.projectkeeper.OsCheck;
+import com.exasol.projectkeeper.OsCheck.OSType;
+
+/**
+ * This class allows building and starting a {@code mvn} command.
+ */
+public class MavenProcessBuilder {
+ private final List command = new ArrayList<>();
+ private Path workingDir = null;
+
+ private MavenProcessBuilder() {
+ // Use create() method
+ }
+
+ /**
+ * Create a new builder.
+ *
+ * @return new builder
+ */
+ public static MavenProcessBuilder create() {
+ final MavenProcessBuilder builder = new MavenProcessBuilder();
+ builder.addArgument(getMavenExecutable());
+ builder.addArgument("--batch-mode");
+ return builder;
+ }
+
+ /**
+ * Add the given arguments to the command.
+ *
+ * @param arguments arguments to add
+ * @return {@code this} for fluent programming
+ */
+ public MavenProcessBuilder addArguments(final String... arguments) {
+ command.addAll(asList(arguments));
+ return this;
+ }
+
+ /**
+ * Add the given argument to the command.
+ *
+ * @param argument argument to add
+ * @return {@code this} for fluent programming
+ */
+ public MavenProcessBuilder addArgument(final String argument) {
+ command.add(argument);
+ return this;
+ }
+
+ /**
+ * Define the working directory where to execute the command. Default: {@code null}.
+ *
+ * @param workingDir working dir
+ * @return {@code this} for fluent programming
+ */
+ public MavenProcessBuilder workingDir(final Path workingDir) {
+ this.workingDir = workingDir;
+ return this;
+ }
+
+ /**
+ * Build the command and run it.
+ *
+ * @return the running {@link SimpleProcess}
+ */
+ public SimpleProcess startSimpleProcess() {
+ return SimpleProcess.start(workingDir, command);
+ }
+
+ private static String getMavenExecutable() {
+ final OSType osType = new OsCheck().getOperatingSystemType();
+ if (osType == OSType.WINDOWS) {
+ return "mvn.cmd";
+ } else {
+ return "mvn";
+ }
+ }
+}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java
index e3030c8f..f5674c74 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java
@@ -8,7 +8,7 @@
import java.util.stream.Stream;
import com.exasol.errorreporting.ExaError;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
/**
* This class list all project-versions by scanning the doc/changes/ folder.
@@ -30,10 +30,10 @@ public VersionCollector(final Path projectDirectory) {
*
* @return list of changes files
*/
- public List collectChangesFiles() {
+ public List collectChangesFiles() {
try (final Stream filesStream = Files.walk(this.projectDirectory.resolve(Path.of("doc", "changes")))) {
return filesStream //
- .map(ChangesFile.Filename::from) //
+ .map(ChangesFileName::from) //
.flatMap(Optional::stream) //
.sorted(Comparator.reverseOrder()) //
.collect(Collectors.toList());
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java
index c7e457c1..86236087 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java
@@ -7,7 +7,7 @@
import com.exasol.errorreporting.ExaError;
import com.exasol.projectkeeper.Validator;
import com.exasol.projectkeeper.validators.VersionCollector;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding;
import com.exasol.projectkeeper.validators.finding.ValidationFinding;
@@ -32,11 +32,11 @@ public LatestChangesFileValidator(final Path projectDir, final String projectVer
@Override
public List validate() {
final List empty = Collections.emptyList();
- final List list = new VersionCollector(this.projectDirectory).collectChangesFiles();
+ final List list = new VersionCollector(this.projectDirectory).collectChangesFiles();
if (list.isEmpty()) {
return empty;
}
- final Filename latest = list.get(0);
+ final ChangesFileName latest = list.get(0);
if (latest.version().equals(this.projectVersion)) {
return empty;
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
index 0d378c26..ea11a2c7 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
@@ -2,8 +2,9 @@
import static com.exasol.projectkeeper.shared.dependencies.BaseDependency.Type.COMPILE;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.FileWriter;
import java.io.IOException;
@@ -44,8 +45,7 @@ void testGetDependencyChanges(@TempDir final Path tempDir) throws GitAPIExceptio
Git.init().setDirectory(tempDir.toFile()).call().close();
final Path pomFile = tempDir.resolve("pom.xml");
writePomFile(pomFile);
- final MavenProjectCrawlResult result = new JavaProjectCrawlerRunner(testMavenRepo,
- TestEnvBuilder.CURRENT_VERSION).crawlProject(pomFile);
+ final MavenProjectCrawlResult result = crawlProject(pomFile);
final CrawledMavenProject mavenProject = result.getCrawledProjects()
.get(pomFile.toAbsolutePath().toString().replace("\\", "/"));
final ProjectDependency expectedDependency = ProjectDependency.builder() //
@@ -63,6 +63,26 @@ void testGetDependencyChanges(@TempDir final Path tempDir) throws GitAPIExceptio
);
}
+ MavenProjectCrawlResult crawlProject(final Path... pomFiles) {
+ return new JavaProjectCrawlerRunner(testMavenRepo, TestEnvBuilder.CURRENT_VERSION).crawlProject(pomFiles);
+ }
+
+ @Test
+ void testGetDependencyChangesFailsForEmptyPomList() throws GitAPIException, IOException {
+ final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> crawlProject());
+ assertThat(exception.getMessage(), containsString(
+ "E-PK-MPC-64: Property 'projectsToCrawl' is not defined or empty. Specify property with least one pom file."));
+ }
+
+ @Test
+ void testGetDependencyChangesFailsForMissingPom() throws GitAPIException, IOException {
+ final Path missingPomFile = Path.of("missing-pom-file");
+ final IllegalStateException exception = assertThrows(IllegalStateException.class,
+ () -> this.crawlProject(missingPomFile));
+ assertThat(exception.getMessage(),
+ allOf(containsString("[FATAL] Non-readable POM"), containsString(missingPomFile.toString())));
+ }
+
private void writePomFile(final Path pomFile) throws IOException {
final TestMavenModel model = new TestMavenModel();
model.addDependency(DEPENDENCY_ID, DEPENDENCY_GROUP, "", DEPENDENCY_VERSION);
@@ -70,4 +90,4 @@ private void writePomFile(final Path pomFile) throws IOException {
new MavenXpp3Writer().write(fileWriter, model);
}
}
-}
\ No newline at end of file
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java
index 3af17dca..9bef4677 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzerTest.java
@@ -30,7 +30,7 @@ void analyzingSourcesWithInvalidOwnVersionFails() {
final IllegalStateException exception = assertThrows(IllegalStateException.class,
() -> analyze(OWN_VERSION, mavenSources));
assertThat(exception.getMessage(),
- allOf(containsString("E-PK-CORE-78: Failed to run command"),
+ allOf(containsString("E-PK-CORE-126: Failed to run command"),
containsString("[ERROR] Plugin com.exasol:project-keeper-java-project-crawler:" + OWN_VERSION
+ " or one of its dependencies could not be resolved")));
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java
index 9a8c7b81..1c9828cc 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcessIT.java
@@ -11,11 +11,11 @@
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;
-// Windows has problems with the timeout of 10ms. Running these tests under Unix is enough.
+// Windows has problems with the timeout of 20ms. Running these tests under Unix is enough.
@DisabledOnOs(OS.WINDOWS)
class SimpleProcessIT {
- private static final Duration TIMEOUT = Duration.ofMillis(10);
+ private static final Duration TIMEOUT = Duration.ofMillis(20);
@Test
void outputStream() {
@@ -60,7 +60,7 @@ void processTimeout() {
final IllegalStateException exception = assertThrows(IllegalStateException.class,
() -> process.waitUntilFinished(TIMEOUT));
assertThat(exception.getMessage(), equalTo(
- "E-PK-CORE-128: Timeout while waiting 10ms for command 'bash -c echo output && >&2 echo error && sleep 1'. Output was 'output'\n"
+ "E-PK-CORE-128: Timeout while waiting 20ms for command 'bash -c echo output && >&2 echo error && sleep 1'. Output was 'output'\n"
+ "Error output: 'error'"));
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java
index 404adc38..e3519302 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java
@@ -11,7 +11,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding;
class LatestChangesFileValidatorTest {
@@ -38,7 +38,7 @@ private LatestChangesFileValidator testee(final Path tempDir, final String... ve
final Path folder = tempDir.resolve(Path.of("doc", "changes"));
Files.createDirectories(folder);
for (final String v : versions) {
- final Filename cfile = new Filename(v);
+ final ChangesFileName cfile = new ChangesFileName(v);
Files.createFile(folder.resolve(cfile.filename()));
}
return new LatestChangesFileValidator(tempDir, "2.0.0");
diff --git a/project-keeper/src/test/resources/changesFileExample1.md b/project-keeper/src/test/resources/changesFileExample1.md
index 4791e2ef..49211dfd 100644
--- a/project-keeper/src/test/resources/changesFileExample1.md
+++ b/project-keeper/src/test/resources/changesFileExample1.md
@@ -49,4 +49,3 @@ My summary
* Added `::`
* Updated `::` to ``
* Removed `::`
-
diff --git a/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java b/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java
index 254fa507..65fea867 100644
--- a/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java
+++ b/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java
@@ -37,6 +37,7 @@ public MavenProjectCrawlResult(final Map crawledPro
* @param json serialized JSON
* @return deserialized {@link DependencyChangeReport}.
*/
+ @SuppressWarnings("try") // Jsonb.close() might throw InterruptedException
public static MavenProjectCrawlResult fromJson(final String json) {
try (final Jsonb jsonb = JsonbBuilder.create()) {
return jsonb.fromJson(json, MavenProjectCrawlResult.class);
@@ -51,6 +52,7 @@ public static MavenProjectCrawlResult fromJson(final String json) {
*
* @return JSON string
*/
+ @SuppressWarnings("try") // Jsonb.close() might throw InterruptedException
public String toJson() {
try (final Jsonb jsonb = JsonbBuilder.create()) {
return jsonb.toJson(this);
diff --git a/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java b/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java
index 7fd42a8d..bbd19c83 100644
--- a/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java
+++ b/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java
@@ -7,7 +7,8 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
-import java.nio.file.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -176,6 +177,7 @@ void testGetRepoName() throws GitAPIException, IOException, URISyntaxException {
}
@Test
+ @SuppressWarnings("try") // auto-closeable resource git is never referenced in body of corresponding try statement
void testFindLatestReleaseCommitNoCommit() throws IllegalStateException, GitAPIException, IOException {
try (final Git git = gitInit()) {
this.repository = openRepo(this.tempDir);
@@ -267,4 +269,4 @@ private GitRepository openRepo(final Path path) {
private Git gitInit() throws GitAPIException {
return Git.init().setDirectory(this.tempDir.toFile()).call();
}
-}
\ No newline at end of file
+}
From 9543d5134553f4c2bc2e1ba875dcd44bb7b99765 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Wed, 7 Feb 2024 12:04:16 +0100
Subject: [PATCH 60/78] Fix compiler warnings
---
.../shared/mavenprojectcrawler/MavenProjectCrawlResult.java | 2 ++
.../projectkeeper/shared/repository/GitRepositoryTest.java | 6 ++++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java b/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java
index 254fa507..65fea867 100644
--- a/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java
+++ b/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/mavenprojectcrawler/MavenProjectCrawlResult.java
@@ -37,6 +37,7 @@ public MavenProjectCrawlResult(final Map crawledPro
* @param json serialized JSON
* @return deserialized {@link DependencyChangeReport}.
*/
+ @SuppressWarnings("try") // Jsonb.close() might throw InterruptedException
public static MavenProjectCrawlResult fromJson(final String json) {
try (final Jsonb jsonb = JsonbBuilder.create()) {
return jsonb.fromJson(json, MavenProjectCrawlResult.class);
@@ -51,6 +52,7 @@ public static MavenProjectCrawlResult fromJson(final String json) {
*
* @return JSON string
*/
+ @SuppressWarnings("try") // Jsonb.close() might throw InterruptedException
public String toJson() {
try (final Jsonb jsonb = JsonbBuilder.create()) {
return jsonb.toJson(this);
diff --git a/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java b/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java
index 7fd42a8d..bbd19c83 100644
--- a/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java
+++ b/shared-model-classes/src/test/java/com/exasol/projectkeeper/shared/repository/GitRepositoryTest.java
@@ -7,7 +7,8 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
-import java.nio.file.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -176,6 +177,7 @@ void testGetRepoName() throws GitAPIException, IOException, URISyntaxException {
}
@Test
+ @SuppressWarnings("try") // auto-closeable resource git is never referenced in body of corresponding try statement
void testFindLatestReleaseCommitNoCommit() throws IllegalStateException, GitAPIException, IOException {
try (final Git git = gitInit()) {
this.repository = openRepo(this.tempDir);
@@ -267,4 +269,4 @@ private GitRepository openRepo(final Path path) {
private Git gitInit() throws GitAPIException {
return Git.init().setDirectory(this.tempDir.toFile()).call();
}
-}
\ No newline at end of file
+}
From 2045a90b02533ad12a4e10d0e6948fead523ecaa Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 8 Feb 2024 04:58:18 +0100
Subject: [PATCH 61/78] Fix compile errors
---
.../exasol/projectkeeper/validators/VersionCollector.java | 6 +++---
.../validators/files/LatestChangesFileValidator.java | 6 +++---
.../validators/files/LatestChangesFileValidatorTest.java | 4 ++--
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java
index f5674c74..e3030c8f 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java
@@ -8,7 +8,7 @@
import java.util.stream.Stream;
import com.exasol.errorreporting.ExaError;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
/**
* This class list all project-versions by scanning the doc/changes/ folder.
@@ -30,10 +30,10 @@ public VersionCollector(final Path projectDirectory) {
*
* @return list of changes files
*/
- public List collectChangesFiles() {
+ public List collectChangesFiles() {
try (final Stream filesStream = Files.walk(this.projectDirectory.resolve(Path.of("doc", "changes")))) {
return filesStream //
- .map(ChangesFileName::from) //
+ .map(ChangesFile.Filename::from) //
.flatMap(Optional::stream) //
.sorted(Comparator.reverseOrder()) //
.collect(Collectors.toList());
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java
index 86236087..afd5cb05 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java
@@ -7,7 +7,7 @@
import com.exasol.errorreporting.ExaError;
import com.exasol.projectkeeper.Validator;
import com.exasol.projectkeeper.validators.VersionCollector;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding;
import com.exasol.projectkeeper.validators.finding.ValidationFinding;
@@ -32,11 +32,11 @@ public LatestChangesFileValidator(final Path projectDir, final String projectVer
@Override
public List validate() {
final List empty = Collections.emptyList();
- final List list = new VersionCollector(this.projectDirectory).collectChangesFiles();
+ final List list = new VersionCollector(this.projectDirectory).collectChangesFiles();
if (list.isEmpty()) {
return empty;
}
- final ChangesFileName latest = list.get(0);
+ final ChangesFile.Filename latest = list.get(0);
if (latest.version().equals(this.projectVersion)) {
return empty;
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java
index e3519302..a030479a 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java
@@ -11,7 +11,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding;
class LatestChangesFileValidatorTest {
@@ -38,7 +38,7 @@ private LatestChangesFileValidator testee(final Path tempDir, final String... ve
final Path folder = tempDir.resolve(Path.of("doc", "changes"));
Files.createDirectories(folder);
for (final String v : versions) {
- final ChangesFileName cfile = new ChangesFileName(v);
+ final ChangesFile.Filename cfile = new ChangesFile.Filename(v);
Files.createFile(folder.resolve(cfile.filename()));
}
return new LatestChangesFileValidator(tempDir, "2.0.0");
From 33480d172df6a80b3ea0bfb537a9fa554e816e1f Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 8 Feb 2024 05:05:50 +0100
Subject: [PATCH 62/78] Add trailing newline
---
shared-model-classes/error_code_config.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/shared-model-classes/error_code_config.yml b/shared-model-classes/error_code_config.yml
index febfbc52..eec657cd 100644
--- a/shared-model-classes/error_code_config.yml
+++ b/shared-model-classes/error_code_config.yml
@@ -2,4 +2,4 @@ error-tags:
PK-SMC:
packages:
- com.exasol.projectkeeper
- highest-index: 81
\ No newline at end of file
+ highest-index: 81
From 0ad2a273f8138e36ef1f1468c4c9c08762113b9c Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 8 Feb 2024 05:16:22 +0100
Subject: [PATCH 63/78] Fix compile errors
---
.../validators/files/LatestChangesFileValidator.java | 6 +++---
.../projectkeeper/validators/VersionCollectorTest.java | 6 +++---
.../validators/files/LatestChangesFileValidatorTest.java | 6 +++---
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java
index afd5cb05..86236087 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java
@@ -7,7 +7,7 @@
import com.exasol.errorreporting.ExaError;
import com.exasol.projectkeeper.Validator;
import com.exasol.projectkeeper.validators.VersionCollector;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding;
import com.exasol.projectkeeper.validators.finding.ValidationFinding;
@@ -32,11 +32,11 @@ public LatestChangesFileValidator(final Path projectDir, final String projectVer
@Override
public List validate() {
final List empty = Collections.emptyList();
- final List list = new VersionCollector(this.projectDirectory).collectChangesFiles();
+ final List list = new VersionCollector(this.projectDirectory).collectChangesFiles();
if (list.isEmpty()) {
return empty;
}
- final ChangesFile.Filename latest = list.get(0);
+ final ChangesFileName latest = list.get(0);
if (latest.version().equals(this.projectVersion)) {
return empty;
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java
index 230506a1..0f178b0f 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java
@@ -40,8 +40,8 @@ void sorted(@TempDir final Path tempDir) throws IOException {
}
private ChangesFileName createChangesFile(final Path folder, final String version) throws IOException {
- final ChangesFileName cfile = new ChangesFileName(version);
- Files.createFile(folder.resolve(cfile.filename()));
- return cfile;
+ final ChangesFileName file = new ChangesFileName(version);
+ Files.createFile(folder.resolve(file.filename()));
+ return file;
}
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java
index a030479a..64ba39c5 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java
@@ -11,7 +11,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding;
class LatestChangesFileValidatorTest {
@@ -38,8 +38,8 @@ private LatestChangesFileValidator testee(final Path tempDir, final String... ve
final Path folder = tempDir.resolve(Path.of("doc", "changes"));
Files.createDirectories(folder);
for (final String v : versions) {
- final ChangesFile.Filename cfile = new ChangesFile.Filename(v);
- Files.createFile(folder.resolve(cfile.filename()));
+ final ChangesFileName file = new ChangesFileName(v);
+ Files.createFile(folder.resolve(file.filename()));
}
return new LatestChangesFileValidator(tempDir, "2.0.0");
}
From 8628d0f4604d0107af1903919e1b48ca65244b5d Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 8 Feb 2024 05:22:11 +0100
Subject: [PATCH 64/78] Parse changesfile
---
.../validators/VersionCollector.java | 6 +-
.../changelog/ChangelogFileGenerator.java | 7 +-
.../changelog/ChangelogFileValidator.java | 6 +-
.../validators/changesfile/ChangesFile.java | 341 +++++++++++-------
.../validators/changesfile/ChangesFileIO.java | 159 ++++++--
.../changesfile/ChangesFileName.java | 83 +++++
.../changesfile/ChangesFileSection.java | 114 ++++--
.../changesfile/ChangesFileValidator.java | 13 +-
.../changesfile/DependencySectionFixer.java | 20 +-
.../DependencyChangeReportRenderer.java | 18 +-
.../files/LatestChangesFileValidator.java | 6 +-
.../validators/VersionCollectorTest.java | 17 +-
.../changelog/ChangelogFileGeneratorTest.java | 8 +-
.../changesfile/ChangesFileIOTest.java | 146 +++++++-
.../changesfile/ChangesFileNameTest.java | 12 +
.../changesfile/ChangesFileSectionTest.java | 13 +
.../changesfile/ChangesFileTest.java | 61 ++++
.../changesfile/ChangesFileValidatorTest.java | 31 +-
.../DependencySectionFixerTest.java | 54 ++-
.../DependencyChangeReportRendererTest.java | 28 +-
.../files/LatestChangesFileValidatorTest.java | 6 +-
21 files changed, 848 insertions(+), 301 deletions(-)
create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileName.java
create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileNameTest.java
create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSectionTest.java
create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java
index e3030c8f..f5674c74 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/VersionCollector.java
@@ -8,7 +8,7 @@
import java.util.stream.Stream;
import com.exasol.errorreporting.ExaError;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
/**
* This class list all project-versions by scanning the doc/changes/ folder.
@@ -30,10 +30,10 @@ public VersionCollector(final Path projectDirectory) {
*
* @return list of changes files
*/
- public List collectChangesFiles() {
+ public List collectChangesFiles() {
try (final Stream filesStream = Files.walk(this.projectDirectory.resolve(Path.of("doc", "changes")))) {
return filesStream //
- .map(ChangesFile.Filename::from) //
+ .map(ChangesFileName::from) //
.flatMap(Optional::stream) //
.sorted(Comparator.reverseOrder()) //
.collect(Collectors.toList());
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGenerator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGenerator.java
index ea1a64f7..8e7ff839 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGenerator.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGenerator.java
@@ -2,8 +2,7 @@
import java.util.List;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
/**
* This class generates the content for the changelog file.
@@ -19,9 +18,9 @@ class ChangelogFileGenerator {
*/
final StringBuilder templateBuilder = new StringBuilder();
- String generate(final List filenames) {
+ String generate(final List filenames) {
this.templateBuilder.append("# Changes" + NL + NL);
- for (final Filename file : filenames) {
+ for (final ChangesFileName file : filenames) {
this.templateBuilder.append("* [" + file.version() + "](" + file.filename() + ")" + NL);
}
return this.templateBuilder.toString();
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileValidator.java
index a6dc485c..111612d0 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileValidator.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileValidator.java
@@ -8,14 +8,14 @@
import com.exasol.projectkeeper.Validator;
import com.exasol.projectkeeper.validators.AbstractFileContentValidator;
import com.exasol.projectkeeper.validators.VersionCollector;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding;
import com.exasol.projectkeeper.validators.finding.ValidationFinding;
/**
* This is a {@link Validator} for the changelog files.
*/
-//[impl->dsn~verify-changelog-file~1]
+// [impl->dsn~verify-changelog-file~1]
public class ChangelogFileValidator extends AbstractFileContentValidator {
private final Path projectDirectory;
@@ -44,7 +44,7 @@ protected List validateContent(final String content) {
@Override
protected String getTemplate() {
- final List versions = new VersionCollector(this.projectDirectory).collectChangesFiles();
+ final List versions = new VersionCollector(this.projectDirectory).collectChangesFiles();
return new ChangelogFileGenerator().generate(versions);
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
index 38e3c4fd..b6e1020b 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
@@ -1,105 +1,47 @@
package com.exasol.projectkeeper.validators.changesfile;
import java.nio.file.Path;
+import java.time.LocalDate;
+import java.time.format.DateTimeParseException;
import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import com.exasol.projectkeeper.mavenrepo.Version;
+import com.exasol.errorreporting.ExaError;
import com.vdurmont.semver4j.Semver;
-import com.vdurmont.semver4j.Semver.SemverType;
/**
* This class represents a doc/changes/changes_x.x.x.md file.
*/
-public class ChangesFile {
+public final class ChangesFile {
/** Headline of the dependency updates section. */
public static final String DEPENDENCY_UPDATES_HEADING = "## Dependency Updates";
- private final List headerSectionLines;
+ /** Headline of the Summary section. */
+ public static final String SUMMARY_HEADING = "## Summary";
+ private final String projectName;
+ private final Semver projectVersion;
+ private final String releaseDate;
+ private final String codeName;
+ private final ChangesFileSection summarySection;
private final List sections;
+ private final ChangesFileSection dependencyChangeSection;
- /**
- * Create a new instance of {@link ChangesFile}.
- *
- * @param headerLines lines of the changes file until the first level section
- * @param sections sections of the changes file
- */
- public ChangesFile(final List headerLines, final List sections) {
- this.headerSectionLines = headerLines;
- this.sections = sections;
+ private ChangesFile(final Builder builder) {
+ this.projectName = builder.projectName;
+ this.projectVersion = builder.projectVersion;
+ this.releaseDate = builder.releaseDate;
+ this.codeName = builder.codeName;
+ this.summarySection = builder.summarySection;
+ this.sections = List.copyOf(builder.sections);
+ this.dependencyChangeSection = builder.dependencyChangeSection;
}
/**
- * Filename of a changes file, e.g. "changes_1.2.3.md".
+ * Get the relative path of the changes file for the given version.
+ *
+ * @param projectVersion project version
+ * @return relative path of the changes file, e.g. {@code doc/changes/changes_1.2.3.md}
*/
- public static class Filename implements Comparable {
- /** Regular expression to identify valid names of changes files and to extract version number. **/
- public static final Pattern PATTERN = Pattern.compile("changes_(" + Version.PATTERN.pattern() + ")\\.md");
-
- /**
- * @param path path to create a {@link Filename} for
- * @return If path matches regular expression for valid changes filenames then an {@link Optional} containing a
- * new instance of {@link Filename}, otherwise {@code Optional.empty()}.
- */
- public static Optional from(final Path path) {
- final String filename = path.getFileName().toString();
- final Matcher matcher = PATTERN.matcher(filename);
- if (!matcher.matches()) {
- return Optional.empty();
- }
- return Optional.of(new Filename(matcher.replaceFirst("$1")));
- }
-
- private final Semver version;
-
- /**
- * Create a new instance of {@link ChangesFile.Filename}.
- *
- * @param version version to use for new instance
- */
- public Filename(final String version) {
- this.version = new Semver(version, SemverType.LOOSE);
- }
-
- /**
- * @return filename of the current {@link ChangesFile.Filename} as string
- */
- public String filename() {
- return "changes_" + this.version + ".md";
- }
-
- @Override
- public int compareTo(final Filename o) {
- return this.version.compareTo(o.version);
- }
-
- /**
- * @return version number contained in the filename of current {@link ChangesFile.Filename}
- */
- public String version() {
- return this.version.getValue();
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(this.version);
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final Filename other = (Filename) obj;
- return Objects.equals(this.version, other.version);
- }
+ public static Path getPathForVersion(final String projectVersion) {
+ return Path.of("doc", "changes", new ChangesFileName(projectVersion).filename());
}
/**
@@ -112,24 +54,65 @@ public static Builder builder() {
}
/**
- * Get the header of the changes section.
- *
- * The header includes all lines until the first section {@code ##} starts.
- *
- *
- * @return list of lines of the header
+ * Get a builder configured with the this ChangesFile. This is useful for creating a copy and modify some parts of
+ * this object.
+ *
+ * @return a preconfigured builder
*/
- public List getHeaderSectionLines() {
- return this.headerSectionLines;
+ public Builder toBuilder() {
+ return builder().projectName(this.projectName).projectVersion(this.projectVersion.toString())
+ .releaseDate(this.releaseDate).codeName(this.codeName).summary(this.summarySection)
+ .sections(List.copyOf(this.sections)).dependencyChangeSection(this.dependencyChangeSection);
}
/**
- * Get the heading of the file.
- *
- * @return heading (1. line)
+ * Get the project name for the first header line, e.g. {@code Project Keeper}.
+ *
+ * @return project name
+ */
+ public String getProjectName() {
+ return projectName;
+ }
+
+ /**
+ * Get the project version for the first header line, e.g. {@code 1.2.3}.
+ *
+ * @return project version
+ */
+ public Semver getProjectVersion() {
+ return projectVersion;
+ }
+
+ /**
+ * Get the release date for the first header line, e.g. {@code 2024-01-29} or {@code 2024-??-??}.
+ *
+ * @return release date
+ */
+ public String getReleaseDate() {
+ return releaseDate;
+ }
+
+ /**
+ * Get the code name of the release.
+ *
+ * @return code name
*/
- public String getHeading() {
- return this.headerSectionLines.get(0);
+ public String getCodeName() {
+ return codeName;
+ }
+
+ /**
+ * Get the parsed release date for the first header line. If the date is not valid (e.g. {@code 2024-??-??}), this
+ * will return an empty {@link Optional}.
+ *
+ * @return release date
+ */
+ public Optional getParsedReleaseDate() {
+ try {
+ return Optional.of(LocalDate.parse(this.getReleaseDate()));
+ } catch (final DateTimeParseException exception) {
+ return Optional.empty();
+ }
}
/**
@@ -141,60 +124,175 @@ public List getSections() {
return this.sections;
}
+ /**
+ * Get the dependency change section.
+ *
+ * @return dependency change section
+ */
+ public Optional getDependencyChangeSection() {
+ return Optional.ofNullable(dependencyChangeSection);
+ }
+
+ /**
+ * Get the summary section.
+ *
+ * @return summary section
+ */
+ public Optional getSummarySection() {
+ return Optional.ofNullable(this.summarySection);
+ }
+
@Override
- public boolean equals(final Object other) {
- if (this == other) {
- return true;
- }
- if ((other == null) || (getClass() != other.getClass())) {
- return false;
- }
- final ChangesFile that = (ChangesFile) other;
- return Objects.equals(this.headerSectionLines, that.headerSectionLines)
- && Objects.equals(this.sections, that.sections);
+ public String toString() {
+ return "ChangesFile [projectName=" + projectName + ", projectVersion=" + projectVersion + ", releaseDate="
+ + releaseDate + ", codeName=" + codeName + ", summarySection=" + summarySection + ", sections="
+ + sections + ", dependencyChangeSection=" + dependencyChangeSection + "]";
}
@Override
public int hashCode() {
- return Objects.hash(this.headerSectionLines, this.sections);
+ return Objects.hash(projectName, projectVersion, releaseDate, codeName, summarySection, sections,
+ dependencyChangeSection);
}
@Override
- public String toString() {
- return String.join("\n", this.headerSectionLines) + "\n"
- + this.sections.stream().map(ChangesFileSection::toString).collect(Collectors.joining("\n"));
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ChangesFile other = (ChangesFile) obj;
+ return Objects.equals(projectName, other.projectName) && Objects.equals(projectVersion, other.projectVersion)
+ && Objects.equals(releaseDate, other.releaseDate) && Objects.equals(codeName, other.codeName)
+ && Objects.equals(summarySection, other.summarySection) && Objects.equals(sections, other.sections)
+ && Objects.equals(dependencyChangeSection, other.dependencyChangeSection);
}
/**
* Builder for {@link ChangesFile}.
*/
public static class Builder {
- private final List sections = new ArrayList<>();
- private List header = Collections.emptyList();
+
+ private String projectName;
+ private Semver projectVersion;
+ private String releaseDate;
+ private String codeName;
+ private ChangesFileSection summarySection;
+ private List sections = new ArrayList<>();
+ private ChangesFileSection dependencyChangeSection;
private Builder() {
// private constructor to hide public default
}
/**
- * Set the header of the changes file.
+ * Set the project name for the first header line, e.g. {@code Project Keeper}.
+ *
+ * @param projectName project name
+ * @return self for fluent programming
+ */
+ public Builder projectName(final String projectName) {
+ this.projectName = projectName;
+ return this;
+ }
+
+ /**
+ * Set the project version for the first header line, e.g. {@code 1.2.3}.
*
- * @param header list of lines
+ * @param projectVersion project version
* @return self for fluent programming
*/
- public Builder setHeader(final List header) {
- this.header = header;
+ public Builder projectVersion(final String projectVersion) {
+ this.projectVersion = new Semver(projectVersion);
+ return this;
+ }
+
+ /**
+ * Set the release date for the first header line, e.g. {@code 2024-01-29} or {@code 2024-??-??}.
+ *
+ * @param releaseDate release date
+ * @return self for fluent programming
+ */
+ public Builder releaseDate(final String releaseDate) {
+ this.releaseDate = releaseDate;
+ return this;
+ }
+
+ /**
+ * Set the code name of the release.
+ *
+ * @param codeName code name
+ * @return self for fluent programming
+ */
+ public Builder codeName(final String codeName) {
+ this.codeName = codeName != null && codeName.isBlank() ? null : codeName;
return this;
}
/**
* Add a section to the changes file.
*
- * @param lines list of lines
+ * @param section section
* @return self for fluent programming
*/
- public Builder addSection(final List lines) {
- this.sections.add(new ChangesFileSection(lines));
+ public Builder addSection(final ChangesFileSection section) {
+ this.sections.add(section);
+ return this;
+ }
+
+ /**
+ * Set the {@code Summary} section for the changes file.
+ *
+ * @param section section
+ * @return self for fluent programming
+ */
+ public Builder summary(final ChangesFileSection section) {
+ if (section == null) {
+ this.summarySection = null;
+ return this;
+ }
+ if (!section.getHeading().equals(SUMMARY_HEADING)) {
+ throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-178").message(
+ "Dependency change section has invalid heading {{heading}}, expected {{expected heading}}",
+ section.getHeading(), SUMMARY_HEADING).ticketMitigation().toString());
+ }
+ this.summarySection = section;
+ return this;
+ }
+
+ /**
+ * Set all sections of the changes file.
+ *
+ * @param sections list of sections
+ * @return self for fluent programming
+ */
+ public Builder sections(final List sections) {
+ this.sections = List.copyOf(sections);
+ return this;
+ }
+
+ /**
+ * Add a an optional {@code Dependency Updates} section to the changes file.
+ *
+ * @param section section
+ * @return self for fluent programming
+ */
+ public Builder dependencyChangeSection(final ChangesFileSection section) {
+ if (section == null) {
+ this.dependencyChangeSection = null;
+ return this;
+ }
+ if (!section.getHeading().equals(DEPENDENCY_UPDATES_HEADING)) {
+ throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-179").message(
+ "Dependency change section has invalid heading {{heading}}, expected {{expected heading}}",
+ section.getHeading(), DEPENDENCY_UPDATES_HEADING).ticketMitigation().toString());
+ }
+ this.dependencyChangeSection = section;
return this;
}
@@ -204,7 +302,8 @@ public Builder addSection(final List lines) {
* @return built {@link ChangesFile}
*/
public ChangesFile build() {
- return new ChangesFile(this.header, this.sections);
+ return new ChangesFile(this);
}
+
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java
index 3853c6f2..6045a3a6 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIO.java
@@ -2,18 +2,24 @@
import java.io.*;
import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.exasol.errorreporting.ExaError;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder;
/**
* This class reads and writes a {@link ChangesFile} from disk.
*/
public class ChangesFileIO {
- private static final Pattern SECTION_HEADING_PATTERN = Pattern.compile("\\s*##\\s.*");
- private static final String LINE_SEPARATOR = System.lineSeparator();
+ private static final String CODE_NAME = "Code name:";
+ private static final String PROJECT_NAME_PATTERN = "[\\w\\s-]+";
+ private static final String VERSION_PATTERN = "\\d+\\.\\d+\\.\\d+";
+ private static final String DATE_PATTERN = "\\d{4}-[\\d?]{2}-[\\d?]{2}";
+ private static final Pattern FIRST_LINE_PATTERN = Pattern
+ .compile("^# (" + PROJECT_NAME_PATTERN + ") (" + VERSION_PATTERN + "), released (" + DATE_PATTERN + ")$");
+ private static final String LINE_SEPARATOR = "\n";
/**
* Read a {@link ChangesFile} from disk.
@@ -23,19 +29,7 @@ public class ChangesFileIO {
*/
public ChangesFile read(final Path file) {
try (final var fileReader = new BufferedReader(new FileReader(file.toFile()))) {
- String sectionHeader = null;
- String line;
- final var builder = ChangesFile.builder();
- final List lineBuffer = new ArrayList<>();
- while ((line = fileReader.readLine()) != null) {
- if (SECTION_HEADING_PATTERN.matcher(line).matches()) {
- makeSection(sectionHeader, builder, lineBuffer);
- sectionHeader = line;
- }
- lineBuffer.add(line);
- }
- makeSection(sectionHeader, builder, lineBuffer);
- return builder.build();
+ return read(file, fileReader);
} catch (final IOException exception) {
throw new IllegalStateException(ExaError.messageBuilder("F-PK-CORE-39")
.message("Failed to read changes file {{file}}.").parameter("file", file.toString()).toString(),
@@ -43,15 +37,85 @@ public ChangesFile read(final Path file) {
}
}
- private void makeSection(final String sectionHeader, final ChangesFile.Builder builder,
- final List lineBuffer) {
- if (!lineBuffer.isEmpty()) {
- if (sectionHeader == null) {
- builder.setHeader(List.copyOf(lineBuffer));
- } else {
- builder.addSection(List.copyOf(lineBuffer));
+ ChangesFile read(final Path file, final BufferedReader fileReader) throws IOException {
+ return new Parser(file, fileReader).parse();
+ }
+
+ private static class Parser {
+ final Path file;
+ final BufferedReader reader;
+ final Builder builder = ChangesFile.builder();
+ ChangesFileSection.Builder currentSection;
+
+ final List lineBuffer = new ArrayList<>();
+ int lineCount = 0;
+
+ Parser(final Path file, final BufferedReader reader) {
+ this.file = file;
+ this.reader = reader;
+ }
+
+ ChangesFile parse() throws IOException {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ parseLine(line);
+ lineCount++;
+ }
+ addSection();
+ return builder.build();
+ }
+
+ private void parseLine(final String line) {
+ if (lineCount == 0) {
+ parseFirstLine(file, line);
+ return;
+ }
+ if (line.startsWith(CODE_NAME)) {
+ builder.codeName(line.substring(CODE_NAME.length()).trim());
+ return;
+ }
+ if (line.startsWith("## ")) {
+ addSection();
+ currentSection = ChangesFileSection.builder(line);
+ return;
+ }
+ if (currentSection != null) {
+ currentSection.addLine(line);
+ }
+ }
+
+ private void addSection() {
+ if (currentSection == null) {
+ return;
+ }
+ final ChangesFileSection section = currentSection.build();
+ currentSection = null;
+ switch (section.getHeading()) {
+ case ChangesFile.SUMMARY_HEADING:
+ builder.summary(section);
+ break;
+ case ChangesFile.DEPENDENCY_UPDATES_HEADING:
+ builder.dependencyChangeSection(section);
+ break;
+ default:
+ builder.addSection(section);
+ break;
+ }
+ }
+
+ private void parseFirstLine(final Path filePath, final String line) {
+ final Matcher matcher = FIRST_LINE_PATTERN.matcher(line);
+ if (!matcher.matches()) {
+ throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-171")
+ .message("Changes file {{file path}} contains invalid first line {{first line}}.", filePath,
+ line)
+ .mitigation("Update first line so that it matches regex {{expected regular expression}}",
+ FIRST_LINE_PATTERN)
+ .toString());
}
- lineBuffer.clear();
+ builder.projectName(matcher.group(1)) //
+ .projectVersion(matcher.group(2)) //
+ .releaseDate(matcher.group(3));
}
}
@@ -62,12 +126,8 @@ private void makeSection(final String sectionHeader, final ChangesFile.Builder b
* @param destinationFile file to write to
*/
public void write(final ChangesFile changesFile, final Path destinationFile) {
- try (final var fileWriter = new BufferedWriter(new FileWriter(destinationFile.toFile()))) {
- writeSection(fileWriter, changesFile.getHeaderSectionLines());
- for (final ChangesFileSection section : changesFile.getSections()) {
- writeSection(fileWriter, section.getContent());
- }
- fileWriter.flush();
+ try (final var writer = new BufferedWriter(new FileWriter(destinationFile.toFile()))) {
+ write(changesFile, writer);
} catch (final IOException exception) {
throw new IllegalStateException(
ExaError.messageBuilder("E-PK-CORE-41").message("Failed to write changes file {{file name}}.")
@@ -76,10 +136,39 @@ public void write(final ChangesFile changesFile, final Path destinationFile) {
}
}
- private void writeSection(final BufferedWriter fileWriter, final List content) throws IOException {
- for (final String line : content) {
- fileWriter.write(line);
- fileWriter.write(LINE_SEPARATOR);
+ void write(final ChangesFile changesFile, final Writer writer) throws IOException {
+ writeHeader(writer, changesFile);
+ for (final ChangesFileSection section : changesFile.getSections()) {
+ writeSection(writer, section);
+ }
+ final Optional dependencyChangeSection = changesFile.getDependencyChangeSection();
+ if (dependencyChangeSection.isPresent()) {
+ writer.write(dependencyChangeSection.get().toString());
+ writer.write(LINE_SEPARATOR);
+ }
+ }
+
+ private void writeHeader(final Writer writer, final ChangesFile changesFile) throws IOException {
+ writer.write("# " + changesFile.getProjectName() + " " + changesFile.getProjectVersion() + ", released "
+ + changesFile.getReleaseDate());
+ writer.write(LINE_SEPARATOR);
+ writer.write(LINE_SEPARATOR);
+ writer.write(CODE_NAME + (changesFile.getCodeName() != null ? " " + changesFile.getCodeName() : ""));
+ writer.write(LINE_SEPARATOR);
+ writer.write(LINE_SEPARATOR);
+ final Optional summarySection = changesFile.getSummarySection();
+ if (summarySection.isPresent()) {
+ writer.write(summarySection.get().toString());
+ writer.write(LINE_SEPARATOR);
+ }
+ }
+
+ private void writeSection(final Writer writer, final ChangesFileSection section) throws IOException {
+ writer.write(section.getHeading());
+ writer.write(LINE_SEPARATOR);
+ for (final String line : section.getContent()) {
+ writer.write(line);
+ writer.write(LINE_SEPARATOR);
}
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileName.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileName.java
new file mode 100644
index 00000000..390c6df5
--- /dev/null
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileName.java
@@ -0,0 +1,83 @@
+package com.exasol.projectkeeper.validators.changesfile;
+
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.exasol.projectkeeper.mavenrepo.Version;
+import com.vdurmont.semver4j.Semver;
+import com.vdurmont.semver4j.Semver.SemverType;
+
+/**
+ * Filename of a changes file, e.g. {@code changes_1.2.3.md}.
+ */
+public final class ChangesFileName implements Comparable {
+ /** Regular expression to identify valid names of changes files and to extract version number. **/
+ public static final Pattern PATTERN = Pattern.compile("changes_(" + Version.PATTERN.pattern() + ")\\.md");
+
+ /**
+ * @param path path to create a {@link ChangesFileName} for
+ * @return If path matches regular expression for valid changes filenames then an {@link Optional} containing a new
+ * instance of {@link ChangesFileName}, otherwise {@code Optional.empty()}.
+ */
+ public static Optional from(final Path path) {
+ final String filename = path.getFileName().toString();
+ final Matcher matcher = PATTERN.matcher(filename);
+ if (!matcher.matches()) {
+ return Optional.empty();
+ }
+ return Optional.of(new ChangesFileName(matcher.replaceFirst("$1")));
+ }
+
+ private final Semver version;
+
+ /**
+ * Create a new instance of {@link ChangesFileName}.
+ *
+ * @param version version to use for new instance
+ */
+ public ChangesFileName(final String version) {
+ this.version = new Semver(version, SemverType.LOOSE);
+ }
+
+ /**
+ * @return filename of the current {@link ChangesFileName} as string
+ */
+ public String filename() {
+ return "changes_" + this.version + ".md";
+ }
+
+ @Override
+ public int compareTo(final ChangesFileName o) {
+ return this.version.compareTo(o.version);
+ }
+
+ /**
+ * @return version number contained in the filename of current {@link ChangesFileName}
+ */
+ public String version() {
+ return this.version.getValue();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(this.version);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ChangesFileName other = (ChangesFileName) obj;
+ return Objects.equals(this.version, other.version);
+ }
+}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java
index b5109bf9..5e5a1ac1 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSection.java
@@ -1,9 +1,8 @@
package com.exasol.projectkeeper.validators.changesfile;
-import java.util.List;
-import java.util.Objects;
+import static java.util.Arrays.asList;
-import com.exasol.errorreporting.ExaError;
+import java.util.*;
/**
* Section of a {@link ChangesFile}.
@@ -11,20 +10,14 @@
* Each level two heading (##) starts a new section.
*
*/
-public class ChangesFileSection {
+public final class ChangesFileSection {
+
+ private final String heading;
private final List content;
- /**
- * Create a new instance of {@link ChangesFileSection}.
- *
- * @param content lines
- */
- public ChangesFileSection(final List content) {
- if (content.isEmpty()) {
- throw new IllegalStateException(ExaError.messageBuilder("F-PK-CORE-36")
- .message("changes file sections must not be empty.").ticketMitigation().toString());
- }
- this.content = content;
+ private ChangesFileSection(final Builder builder) {
+ this.heading = Objects.requireNonNull(builder.heading, "header");
+ this.content = List.copyOf(builder.lines);
}
/**
@@ -33,7 +26,7 @@ public ChangesFileSection(final List content) {
* @return heading
*/
public String getHeading() {
- return this.content.get(0);
+ return this.heading;
}
/**
@@ -46,22 +39,91 @@ public List getContent() {
}
@Override
- public boolean equals(final Object other) {
- if (this == other)
- return true;
- if (other == null || getClass() != other.getClass())
- return false;
- final ChangesFileSection that = (ChangesFileSection) other;
- return Objects.equals(this.content, that.content);
+ public int hashCode() {
+ return Objects.hash(heading, content);
}
@Override
- public int hashCode() {
- return Objects.hash(this.content);
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ChangesFileSection other = (ChangesFileSection) obj;
+ return Objects.equals(heading, other.heading) && Objects.equals(content, other.content);
}
@Override
public String toString() {
- return String.join("\n", this.content);
+ return heading + "\n" + String.join("\n", this.content);
+ }
+
+ /**
+ * Create a new {@link Builder} for creating a {@link ChangesFileSection}.
+ *
+ * @param heading the heading for the new section
+ * @return a new builder
+ */
+ public static Builder builder(final String heading) {
+ return new Builder(heading);
+ }
+
+ /**
+ * A builder for creating {@link ChangesFileSection}s.
+ */
+ public static class Builder {
+ private final String heading;
+ private final List lines = new ArrayList<>();
+
+ private Builder(final String heading) {
+ this.heading = heading;
+ }
+
+ /**
+ * Add the given lines to the content of the new {@code ChangesFileSection}.
+ *
+ * @param lines lines to add
+ * @return {@code this} for fluent programming
+ */
+ public Builder addLines(final String... lines) {
+ this.lines.addAll(asList(lines));
+ return this;
+ }
+
+ /**
+ * Add the given lines to the content of the new {@code ChangesFileSection}.
+ *
+ * @param lines lines to add
+ * @return {@code this} for fluent programming
+ */
+ public Builder addLines(final List lines) {
+ this.lines.addAll(lines);
+ return this;
+ }
+
+ /**
+ * Add the given line to the content of the new {@code ChangesFileSection}.
+ *
+ * @param line line to add
+ * @return {@code this} for fluent programming
+ */
+ public Builder addLine(final String line) {
+ this.lines.add(line);
+ return this;
+ }
+
+ /**
+ * Build a new {@link ChangesFileSection}.
+ *
+ * @return a new {@link ChangesFileSection}.
+ */
+ public ChangesFileSection build() {
+ return new ChangesFileSection(this);
+ }
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java
index 30a8bb5b..ba21db83 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidator.java
@@ -31,7 +31,7 @@ public class ChangesFileValidator extends AbstractFileValidator {
*/
public ChangesFileValidator(final String projectVersion, final String projectName, final Path projectDirectory,
final List sources) {
- super(projectDirectory, Path.of("doc", "changes", new ChangesFile.Filename(projectVersion).filename()));
+ super(projectDirectory, ChangesFile.getPathForVersion(projectVersion));
this.projectVersion = projectVersion;
this.projectName = projectName;
this.sources = sources;
@@ -72,10 +72,13 @@ private ChangesFile fixSections(final ChangesFile changesFile) {
}
private ChangesFile getTemplate() {
- final var changesFile = ChangesFile.builder()
- .setHeader(List.of("# " + this.projectName + " " + this.projectVersion + ", released "
- + LocalDateTime.now().getYear() + "-??-??", "", "Code name:", "")) //
- .addSection(List.of("## Summary", "", "## Features", "", "* ISSUE_NUMBER: description", "")) //
+ final String releaseDate = LocalDateTime.now().getYear() + "-??-??";
+ final var changesFile = ChangesFile.builder().projectName(this.projectName).projectVersion(this.projectVersion)
+ .releaseDate(releaseDate) //
+ .codeName("") //
+ .summary(ChangesFileSection.builder("## Summary").build())
+ .addSection(ChangesFileSection.builder("## Features").addLines("", "* ISSUE_NUMBER: description", "")
+ .build()) //
.build();
return fixSections(changesFile);
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java
index 01a08241..9db14cf0 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixer.java
@@ -1,9 +1,7 @@
package com.exasol.projectkeeper.validators.changesfile;
-import static com.exasol.projectkeeper.validators.changesfile.ChangesFile.DEPENDENCY_UPDATES_HEADING;
-
-import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import java.util.stream.Collectors;
import com.exasol.projectkeeper.sources.AnalyzedSource;
@@ -12,7 +10,7 @@
/**
* This class fixes the dependency section of a {@link ChangesFile}.
*/
-//[impl->dsn~dependency-section-in-changes_x.x.x.md-file-validator~1]
+// [impl->dsn~dependency-section-in-changes_x.x.x.md-file-validator~1]
class DependencySectionFixer {
private final List sources;
@@ -35,20 +33,12 @@ public DependencySectionFixer(final List sources) {
public ChangesFile fix(final ChangesFile changesFile) {
final List reports = this.sources.stream().map(this::getDependencyChangesOfSource)
.collect(Collectors.toList());
- final List renderedReport = new DependencyChangeReportRenderer().render(reports);
- final List sections = new ArrayList<>(changesFile.getSections());
- removeDependencySection(sections);
- if (!renderedReport.isEmpty()) {
- sections.add(new ChangesFileSection(renderedReport));
- }
- return new ChangesFile(List.copyOf(changesFile.getHeaderSectionLines()), sections);
+ final Optional dependencyChanges = new DependencyChangeReportRenderer().render(reports);
+ return changesFile.toBuilder() //
+ .dependencyChangeSection(dependencyChanges.orElse(null)).build();
}
private NamedDependencyChangeReport getDependencyChangesOfSource(final AnalyzedSource source) {
return new NamedDependencyChangeReport(source.getProjectName(), source.getDependencyChanges());
}
-
- private void removeDependencySection(final List sections) {
- sections.removeIf(section -> section.getHeading().compareToIgnoreCase(DEPENDENCY_UPDATES_HEADING) == 0);
- }
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java
index aca0d23d..34695e34 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRenderer.java
@@ -2,14 +2,12 @@
import static com.exasol.projectkeeper.ApStyleFormatter.capitalizeApStyle;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
import com.exasol.projectkeeper.shared.dependencies.BaseDependency.Type;
import com.exasol.projectkeeper.shared.dependencychanges.DependencyChange;
import com.exasol.projectkeeper.shared.dependencychanges.DependencyChangeReport;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
-import com.exasol.projectkeeper.validators.changesfile.NamedDependencyChangeReport;
+import com.exasol.projectkeeper.validators.changesfile.*;
/**
* String renderer for {@link DependencyChangeReport}.
@@ -20,17 +18,15 @@ public class DependencyChangeReportRenderer {
* Render a {@link DependencyChangeReport} to string.
*
* @param reports reports to render
- * @return rendered report as a list of lines
+ * @return rendered report as a section
*/
- public List render(final List reports) {
+ public Optional render(final List reports) {
final List content = renderContent(reports);
- final List lines = new ArrayList<>();
if (content.isEmpty()) {
- return lines;
+ return Optional.empty();
}
- lines.add(ChangesFile.DEPENDENCY_UPDATES_HEADING);
- lines.addAll(content);
- return lines;
+ return Optional.of(ChangesFileSection.builder(ChangesFile.DEPENDENCY_UPDATES_HEADING) //
+ .addLines(content).build());
}
private List renderContent(final List reports) {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java
index afd5cb05..86236087 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidator.java
@@ -7,7 +7,7 @@
import com.exasol.errorreporting.ExaError;
import com.exasol.projectkeeper.Validator;
import com.exasol.projectkeeper.validators.VersionCollector;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding;
import com.exasol.projectkeeper.validators.finding.ValidationFinding;
@@ -32,11 +32,11 @@ public LatestChangesFileValidator(final Path projectDir, final String projectVer
@Override
public List validate() {
final List empty = Collections.emptyList();
- final List list = new VersionCollector(this.projectDirectory).collectChangesFiles();
+ final List list = new VersionCollector(this.projectDirectory).collectChangesFiles();
if (list.isEmpty()) {
return empty;
}
- final ChangesFile.Filename latest = list.get(0);
+ final ChangesFileName latest = list.get(0);
if (latest.version().equals(this.projectVersion)) {
return empty;
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java
index 56c91af0..0f178b0f 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/VersionCollectorTest.java
@@ -13,8 +13,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Filename;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
class VersionCollectorTest {
@Test
@@ -29,20 +28,20 @@ void sorted(@TempDir final Path tempDir) throws IOException {
"1.0.0")) {
createChangesFile(folder, version);
}
- final List expected = Stream.of( //
+ final List expected = Stream.of( //
"1.1.0", //
"1.0.10", //
"1.0.2", //
"1.0.0", //
"0.3.0") //
- .map(ChangesFile.Filename::new) //
+ .map(ChangesFileName::new) //
.collect(Collectors.toList());
assertThat(new VersionCollector(tempDir).collectChangesFiles(), equalTo(expected));
}
- private ChangesFile.Filename createChangesFile(final Path folder, final String version) throws IOException {
- final Filename cfile = new Filename(version);
- Files.createFile(folder.resolve(cfile.filename()));
- return cfile;
+ private ChangesFileName createChangesFile(final Path folder, final String version) throws IOException {
+ final ChangesFileName file = new ChangesFileName(version);
+ Files.createFile(folder.resolve(file.filename()));
+ return file;
}
-}
\ No newline at end of file
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGeneratorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGeneratorTest.java
index 58a45393..3f66983a 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGeneratorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changelog/ChangelogFileGeneratorTest.java
@@ -12,7 +12,7 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
class ChangelogFileGeneratorTest {
@Test
@@ -27,7 +27,7 @@ void testNonStandardVersionFormats(final String version) {
assertThat(new ChangelogFileGenerator().generate(files(version)), containsString(version));
}
- private List files(final String... versions) {
- return Arrays.stream(versions).map(ChangesFile.Filename::new).collect(Collectors.toList());
+ private List files(final String... versions) {
+ return Arrays.stream(versions).map(ChangesFileName::new).collect(Collectors.toList());
}
-}
\ No newline at end of file
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java
index 191984a6..3f7748c1 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileIOTest.java
@@ -1,12 +1,13 @@
package com.exasol.projectkeeper.validators.changesfile;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.contains;
-import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertThrows;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
import java.nio.file.*;
+import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@@ -24,37 +25,142 @@ void testParsing() throws IOException {
final ChangesFile changesFile = new ChangesFileIO().read(changesFilePath);
final List headings = changesFile.getSections().stream().map(ChangesFileSection::getHeading)
.collect(Collectors.toList());
- assertThat(changesFile.getHeading(), equalTo("# My Project 0.1.0, released 1980-01-01"));
- assertThat(headings, contains("## Summary", "## Features", "## Bug Fixes", "## Documentation", "## Refactoring",
- "## Dependency Updates"));
+ assertThat(changesFile.getProjectName(), equalTo("My Project"));
+ assertThat(changesFile.getProjectVersion().toString(), equalTo("0.1.0"));
+ assertThat(changesFile.getReleaseDate(), equalTo("1980-01-01"));
+ assertThat(changesFile.getParsedReleaseDate().get(), equalTo(LocalDate.parse("1980-01-01")));
+ assertThat(changesFile.getSummarySection().get().getContent(), contains("", "My summary", ""));
+ assertThat(headings, contains("## Features", "## Bug Fixes", "## Documentation", "## Refactoring"));
+ assertThat(changesFile.getDependencyChangeSection().get().getHeading(), equalTo("## Dependency Updates"));
+ assertThat(changesFile.getDependencyChangeSection().get().getContent(), hasSize(18));
}
@Test
void testWriting() throws IOException {
- final ChangesFile changesFile = ChangesFile.builder().setHeader(List.of("# MyChanges"))
- .addSection(List.of("## My Subsection")).build();
+ final ChangesFile changesFile = ChangesFile.builder().projectName("project").projectVersion("1.2.3")
+ .releaseDate("2023-??-??").codeName("my code name")
+ .summary(ChangesFileSection.builder("## Summary").addLine("my summary content").build())
+ .addSection(ChangesFileSection.builder("# MyChanges").build())
+ .addSection(ChangesFileSection.builder("## My Subsection").addLine("content").build()).build();
final Path testFile = this.tempDir.resolve("myFile.md");
new ChangesFileIO().write(changesFile, testFile);
- assertThat(Files.readString(testFile),
- equalTo("# MyChanges" + System.lineSeparator() + "## My Subsection" + System.lineSeparator()));
+ assertThat(Files.readString(testFile), equalTo(
+ "# project 1.2.3, released 2023-??-??\n\nCode name: my code name\n\n## Summary\nmy summary content\n# MyChanges\n## My Subsection\ncontent\n"));
}
@Test
void testReadAndWrite() throws IOException {
- final Path changesFilePath = loadExampleFileToTempDir();
- final ChangesFileIO changesFileIO = new ChangesFileIO();
- final ChangesFile changesFile = changesFileIO.read(changesFilePath);
- final Path testFile = this.tempDir.resolve("result.md");
- changesFileIO.write(changesFile, testFile);
- assertThat(Files.readString(testFile), equalTo(Files.readString(changesFilePath)));
+ final String content = readExampleFile();
+ assertReadWrite(content);
+ }
+
+ @Test
+ void testReadInvalidFirstLineFails() {
+ final IllegalStateException exception = assertThrows(IllegalStateException.class,
+ () -> readFromString("# invalid first line"));
+ assertThat(exception.getMessage(), startsWith(
+ "E-PK-CORE-171: Changes file 'dummy-file' contains invalid first line '# invalid first line'. Update first line so that it matches regex"));
+ }
+
+ @Test
+ void testReadFirstLineWithDummyReleaseDate() throws IOException {
+ final ChangesFile changesFile = readFromString(
+ "# Project Name 1.2.3, released 2024-??-??\nCode name: my code name\n## Summary\n\n");
+ assertThat(changesFile.getProjectName(), equalTo("Project Name"));
+ assertThat(changesFile.getProjectVersion().toString(), equalTo("1.2.3"));
+ assertThat(changesFile.getReleaseDate(), equalTo("2024-??-??"));
+ assertThat(changesFile.getCodeName(), equalTo("my code name"));
+ assertThat(changesFile.getParsedReleaseDate().isPresent(), is(false));
+ assertWriteRead(changesFile);
+ }
+
+ @Test
+ void testReadFirstLineWithValidReleaseDate() throws IOException {
+ final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29\n## Summary\n\n");
+ assertThat(changesFile.getProjectName(), equalTo("Project Name"));
+ assertThat(changesFile.getProjectVersion().toString(), equalTo("1.2.3"));
+ assertThat(changesFile.getReleaseDate(), equalTo("2024-01-29"));
+ assertThat(changesFile.getParsedReleaseDate().get(), equalTo(LocalDate.parse("2024-01-29")));
+ assertWriteRead(changesFile);
+ }
+
+ @Test
+ void testReadMissingSummary() throws IOException {
+ final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29");
+ assertThat(changesFile.getSummarySection().isEmpty(), is(true));
+ }
+
+ @Test
+ void testReadEmptySummary() throws IOException {
+ final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29\n## Summary");
+ final ChangesFileSection summary = changesFile.getSummarySection().get();
+ assertThat(summary.getHeading(), equalTo("## Summary"));
+ assertThat(summary.getContent(), emptyIterable());
+ }
+
+ @Test
+ void testReadSummary() throws IOException {
+ final ChangesFile changesFile = readFromString(
+ "# Project Name 1.2.3, released 2024-01-29\n## Summary\nmy\ncontent\n");
+ final ChangesFileSection summary = changesFile.getSummarySection().get();
+ assertThat(summary.getHeading(), equalTo("## Summary"));
+ assertThat(summary.getContent(), contains("my", "content"));
+ assertWriteRead(changesFile);
+ }
+
+ @Test
+ void testReadNoDependencySection() throws IOException {
+ final ChangesFile changesFile = readFromString("# Project Name 1.2.3, released 2024-01-29\n## Summary");
+ assertThat(changesFile.getDependencyChangeSection().isEmpty(), is(true));
+ }
+
+ @Test
+ void testReadDependencySection() throws IOException {
+ final ChangesFile changesFile = readFromString(
+ "# Project Name 1.2.3, released 2024-01-29\n## Summary\n## Dependency Updates\nmy\ncontent");
+ assertThat(changesFile.getDependencyChangeSection().isEmpty(), is(false));
+ assertThat(changesFile.getDependencyChangeSection().get().getHeading(), equalTo("## Dependency Updates"));
+ assertThat(changesFile.getDependencyChangeSection().get().getContent(), contains("my", "content"));
}
private Path loadExampleFileToTempDir() throws IOException {
final Path changesFile = this.tempDir.resolve("changed_0.1.0.md");
- try (final InputStream exampleFileStream = getClass().getClassLoader()
- .getResourceAsStream("changesFileExample1.md")) {
+ try (final InputStream exampleFileStream = getExampleFileStream()) {
Files.copy(Objects.requireNonNull(exampleFileStream), changesFile, StandardCopyOption.REPLACE_EXISTING);
}
return changesFile;
}
-}
\ No newline at end of file
+
+ private String readExampleFile() throws IOException {
+ try (final InputStream exampleFileStream = getExampleFileStream()) {
+ return new String(exampleFileStream.readAllBytes(), StandardCharsets.UTF_8).replace("\r\n", "\n");
+ }
+ }
+
+ private InputStream getExampleFileStream() {
+ return getClass().getClassLoader().getResourceAsStream("changesFileExample1.md");
+ }
+
+ private void assertWriteRead(final ChangesFile changesFile) throws IOException {
+ final String content = writeToString(changesFile);
+ final ChangesFile readChangesFile = readFromString(content);
+ assertThat(readChangesFile.toString(), equalTo(changesFile.toString()));
+ assertThat(readChangesFile, equalTo(changesFile));
+ }
+
+ private void assertReadWrite(final String content) throws IOException {
+ final ChangesFile changesFile = readFromString(content);
+ final String writtenContent = writeToString(changesFile);
+ assertThat(writtenContent, equalTo(content));
+ }
+
+ private String writeToString(final ChangesFile changesFile) throws IOException {
+ final StringWriter stringWriter = new StringWriter();
+ new ChangesFileIO().write(changesFile, stringWriter);
+ return stringWriter.toString();
+ }
+
+ private ChangesFile readFromString(final String content) throws IOException {
+ return new ChangesFileIO().read(Path.of("dummy-file"), new BufferedReader(new StringReader(content)));
+ }
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileNameTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileNameTest.java
new file mode 100644
index 00000000..d1a792ee
--- /dev/null
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileNameTest.java
@@ -0,0 +1,12 @@
+package com.exasol.projectkeeper.validators.changesfile;
+
+import org.junit.jupiter.api.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class ChangesFileNameTest {
+ @Test
+ void equalsContractFilename() {
+ EqualsVerifier.forClass(ChangesFileName.class).verify();
+ }
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSectionTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSectionTest.java
new file mode 100644
index 00000000..929afba6
--- /dev/null
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileSectionTest.java
@@ -0,0 +1,13 @@
+package com.exasol.projectkeeper.validators.changesfile;
+
+import org.junit.jupiter.api.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class ChangesFileSectionTest {
+
+ @Test
+ void equalsContract() {
+ EqualsVerifier.forClass(ChangesFileSection.class).verify();
+ }
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java
new file mode 100644
index 00000000..d4b3ab20
--- /dev/null
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileTest.java
@@ -0,0 +1,61 @@
+package com.exasol.projectkeeper.validators.changesfile;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+
+import java.nio.file.Path;
+import java.time.LocalDate;
+
+import org.junit.jupiter.api.Test;
+
+import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder;
+import com.jparams.verifier.tostring.ToStringVerifier;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class ChangesFileTest {
+
+ @Test
+ void equalsContract() {
+ EqualsVerifier.forClass(ChangesFile.class).verify();
+ }
+
+ @Test
+ void testToString() {
+ ToStringVerifier.forClass(ChangesFile.class).verify();
+ }
+
+ @Test
+ void getPathForVersion() {
+ assertThat(ChangesFile.getPathForVersion("1.2.3"), equalTo(Path.of("doc/changes/changes_1.2.3.md")));
+ }
+
+ @Test
+ void toBuilderCreatesCopy() {
+ final ChangesFile changesFile = builder().build();
+ final ChangesFile copy = changesFile.toBuilder().build();
+ assertThat(copy, equalTo(changesFile));
+ assertThat(changesFile.equals(copy), is(true));
+ }
+
+ private Builder builder() {
+ return ChangesFile.builder().projectName("name").projectVersion("1.2.3").releaseDate("2023-??-??")
+ .codeName("my code name")
+ .summary(ChangesFileSection.builder("## Summary").addLine("summary content").build())
+ .dependencyChangeSection(ChangesFileSection.builder("## Dependency Updates")
+ .addLine("dependency update content").build())
+ .addSection(ChangesFileSection.builder("section 1").build());
+ }
+
+ @Test
+ void getParsedReleaseDateValid() {
+ assertThat(builder().releaseDate("2024-01-29").build().getParsedReleaseDate().get(),
+ equalTo(LocalDate.of(2024, 1, 29)));
+ }
+
+ @Test
+ void getParsedReleaseDateInvalid() {
+ assertThat(builder().releaseDate("invalid").build().getParsedReleaseDate().isPresent(), is(false));
+ }
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java
index 9cf9bf31..62234975 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/ChangesFileValidatorTest.java
@@ -4,10 +4,8 @@
import static com.exasol.projectkeeper.HasNoMoreFindingsAfterApplyingFixesMatcher.hasNoMoreFindingsAfterApplyingFixes;
import static com.exasol.projectkeeper.HasValidationFindingWithMessageMatcher.hasNoValidationFindings;
import static com.exasol.projectkeeper.HasValidationFindingWithMessageMatcher.hasValidationFindingWithMessage;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -35,6 +33,7 @@
class ChangesFileValidatorTest {
private static final String A_VERSION = "1.2.3";
private static final String A_PROJECT_NAME = "my-project";
+ private static final String LINE_SEPARATOR = "\n";
@TempDir
Path tempDir;
@@ -55,12 +54,18 @@ void testValidationForSnapshotVersion() throws IOException {
}
@Test
- void noDepdendencyUpdates() throws IOException {
+ void noDependencyUpdates() throws IOException {
final AnalyzedMavenSource source = createTestSetup(new TestMavenModel(), Collections.emptyList());
final Logger log = mock(Logger.class);
createValidator(source).validate().forEach(finding -> new FindingsFixer(log).fixFindings(List.of(finding)));
final Path changesFile = this.tempDir.resolve(Path.of("doc", "changes", "changes_1.2.3.md"));
- assertThat(changesFile, hasContent(startsWith("# my-project 1.2.3, release")));
+ assertThat(changesFile,
+ hasContent(equalTo("# my-project 1.2.3, released 2024-??-??" + LINE_SEPARATOR + LINE_SEPARATOR //
+ + "Code name:" + LINE_SEPARATOR + LINE_SEPARATOR //
+ + "## Summary" + LINE_SEPARATOR + LINE_SEPARATOR //
+ + "## Features" + LINE_SEPARATOR + LINE_SEPARATOR //
+ + "* ISSUE_NUMBER: description" + LINE_SEPARATOR + LINE_SEPARATOR)));
+
verify(log).info("Created 'doc" + File.separator + "changes" + File.separator
+ "changes_1.2.3.md'. Don't forget to update its content!");
final List findings = createValidator(source).validate();
@@ -73,7 +78,15 @@ void testFixCreatedTemplate() throws IOException {
final Logger log = mock(Logger.class);
createValidator(source).validate().forEach(finding -> new FindingsFixer(log).fixFindings(List.of(finding)));
final Path changesFile = this.tempDir.resolve(Path.of("doc", "changes", "changes_1.2.3.md"));
- assertThat(changesFile, hasContent(startsWith("# my-project 1.2.3, release")));
+ assertThat(changesFile,
+ hasContent(equalTo("# my-project 1.2.3, released 2024-??-??" + LINE_SEPARATOR + LINE_SEPARATOR //
+ + "Code name:" + LINE_SEPARATOR + LINE_SEPARATOR //
+ + "## Summary" + LINE_SEPARATOR + LINE_SEPARATOR //
+ + "## Features" + LINE_SEPARATOR + LINE_SEPARATOR //
+ + "* ISSUE_NUMBER: description" + LINE_SEPARATOR + LINE_SEPARATOR //
+ + "## Dependency Updates" + LINE_SEPARATOR + LINE_SEPARATOR //
+ + "### Compile Dependency Updates" + LINE_SEPARATOR + LINE_SEPARATOR
+ + "* Added `com.example:my-lib:1.2.3`" + LINE_SEPARATOR)));
verify(log).info("Created 'doc" + File.separator + "changes" + File.separator
+ "changes_1.2.3.md'. Don't forget to update its content!");
}
@@ -85,7 +98,9 @@ void testFixContainsDependencyUpdates() throws IOException {
final AnalyzedMavenSource source = createTestSetup(model);
createValidator(source).validate().forEach(FindingFixHelper::fix);
final Path changesFile = this.tempDir.resolve(Path.of("doc", "changes", "changes_1.2.3.md"));
- assertThat(changesFile, hasContent(containsString("my-lib")));
+ assertThat(changesFile, hasContent(endsWith("## Dependency Updates" + LINE_SEPARATOR + LINE_SEPARATOR //
+ + "### Compile Dependency Updates" + LINE_SEPARATOR + LINE_SEPARATOR //
+ + "* Added `com.example:my-lib:1.2.3`" + LINE_SEPARATOR)));
}
@Test
@@ -117,4 +132,4 @@ private AnalyzedMavenSource createTestSetup(final TestMavenModel mavenModel,
.dependencyChanges(DependencyChangeReport.builder().typed(Type.COMPILE, dependencyChanges).build()) //
.build();
}
-}
\ No newline at end of file
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java
index 90ca108e..d02f8e7f 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/DependencySectionFixerTest.java
@@ -2,8 +2,7 @@
import static com.exasol.projectkeeper.validators.changesfile.ChangesFile.DEPENDENCY_UPDATES_HEADING;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.*;
import java.util.List;
@@ -13,9 +12,10 @@
import com.exasol.projectkeeper.shared.dependencychanges.DependencyChangeReport;
import com.exasol.projectkeeper.shared.dependencychanges.NewDependency;
import com.exasol.projectkeeper.sources.AnalyzedMavenSource;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder;
@Tag("integration")
-//[utest->dsn~dependency-section-in-changes_x.x.x.md-file-validator~1]
+// [utest->dsn~dependency-section-in-changes_x.x.x.md-file-validator~1]
class DependencySectionFixerTest {
private static AnalyzedMavenSource source;
@@ -32,29 +32,43 @@ static void beforeAll() {
@Test
void testSectionIsAdded() {
- final ChangesFile changesFile = ChangesFile.builder().setHeader(List.of("heading")).build();
- final List sections = new DependencySectionFixer(List.of(source)).fix(changesFile)
- .getSections();
- assertThat(sections.size(), equalTo(1));
- assertThat(sections.get(0).getHeading(), equalTo(DEPENDENCY_UPDATES_HEADING));
+ final ChangesFile changesFile = changesFileBuilder().addSection(ChangesFileSection.builder("heading").build())
+ .build();
+ final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile);
+ assertThat(fixedChangesFile.getDependencyChangeSection().get().getHeading(),
+ equalTo(DEPENDENCY_UPDATES_HEADING));
+ }
+
+ private Builder changesFileBuilder() {
+ return ChangesFile.builder().projectName("projectName").projectVersion("1.2.3").releaseDate("releaseDate")
+ .summary(ChangesFileSection.builder("## Summary").build());
}
@Test
void testSectionIsUpdated() {
- final ChangesFile changesFile = ChangesFile.builder().setHeader(List.of("heading"))
- .addSection(List.of(DEPENDENCY_UPDATES_HEADING, "myLine")).build();
+ final ChangesFile changesFile = changesFileBuilder().dependencyChangeSection(
+ ChangesFileSection.builder("## Dependency Updates").addLine("content will be overwritten").build())
+ .build();
final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile);
- final List sections = fixedChangesFile.getSections();
- assertThat(sections.size(), equalTo(1));
- assertThat(sections.get(0).getHeading(), equalTo(DEPENDENCY_UPDATES_HEADING));
- assertThat("dependency fixer changed the changes file", changesFile, not(equalTo(fixedChangesFile)));
+ final ChangesFileSection changesFileSection = fixedChangesFile.getDependencyChangeSection().get();
+ assertThat(changesFileSection.getHeading(), equalTo(DEPENDENCY_UPDATES_HEADING));
+ assertThat(changesFileSection.getContent(),
+ contains("", "### Compile Dependency Updates", "", "* Added `com.example:my-lib:1.2.3`"));
+ assertThat("dependency fixer changed the changes file", changesFile,
+ allOf(not(equalTo(fixedChangesFile)), not(sameInstance(fixedChangesFile))));
}
@Test
- void testHeaderIsPreserved() {
- final ChangesFile changesFile = ChangesFile.builder().setHeader(List.of("heading"))
- .addSection(List.of(DEPENDENCY_UPDATES_HEADING, "myLine")).build();
- final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of(source)).fix(changesFile);
- assertThat(changesFile.getHeaderSectionLines(), equalTo(fixedChangesFile.getHeaderSectionLines()));
+ void testDependencySectionIsRemoved() {
+ final ChangesFile changesFile = changesFileBuilder().addSection(ChangesFileSection.builder("heading").build())
+ .dependencyChangeSection(ChangesFileSection.builder("## Dependency Updates")
+ .addLine("content will be preserved").build())
+ .build();
+ final ChangesFile fixedChangesFile = new DependencySectionFixer(List.of()).fix(changesFile);
+
+ assertThat(fixedChangesFile.getDependencyChangeSection().isPresent(), is(false));
+ assertThat(fixedChangesFile, not(sameInstance(changesFile)));
+ assertThat("dependency fixer changed the changes file", changesFile,
+ allOf(not(equalTo(fixedChangesFile)), not(sameInstance(fixedChangesFile))));
}
-}
\ No newline at end of file
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java
index 6ad5cde4..12eb1942 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/changesfile/dependencies/DependencyChangeReportRendererTest.java
@@ -1,16 +1,19 @@
package com.exasol.projectkeeper.validators.changesfile.dependencies;
+import static java.util.Arrays.asList;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.emptyString;
import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
import java.util.List;
+import java.util.Optional;
import org.junit.jupiter.api.Test;
import com.exasol.projectkeeper.shared.dependencies.BaseDependency.Type;
import com.exasol.projectkeeper.shared.dependencychanges.DependencyChangeReport;
import com.exasol.projectkeeper.shared.dependencychanges.NewDependency;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileSection;
import com.exasol.projectkeeper.validators.changesfile.NamedDependencyChangeReport;
class DependencyChangeReportRendererTest {
@@ -22,17 +25,15 @@ class DependencyChangeReportRendererTest {
@Test
void testRenderSingleSourceReport() {
final NamedDependencyChangeReport namedReport = new NamedDependencyChangeReport("my-project", REPORT);
- final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(namedReport)));
- assertThat(result, equalTo("## Dependency Updates\n" + "\n" + "### Compile Dependency Updates\n" + "\n"
- + "* Added `com.example:my-lib:1.2.3`"));
+ assertThat(render(namedReport), equalTo("## Dependency Updates\n" + "\n" + "### Compile Dependency Updates\n"
+ + "\n" + "* Added `com.example:my-lib:1.2.3`"));
}
@Test
void testRenderMultiSourceReport() {
final NamedDependencyChangeReport sourceA = new NamedDependencyChangeReport("project A", REPORT);
final NamedDependencyChangeReport sourceB = new NamedDependencyChangeReport("project B", REPORT);
- final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(sourceA, sourceB)));
- assertThat(result, equalTo(
+ assertThat(render(sourceA, sourceB), equalTo(
"## Dependency Updates\n\n### Project A\n\n#### Compile Dependency Updates\n\n* Added `com.example:my-lib:1.2.3`\n\n### Project B\n\n#### Compile Dependency Updates\n\n* Added `com.example:my-lib:1.2.3`"));
}
@@ -40,15 +41,20 @@ void testRenderMultiSourceReport() {
void testRenderMultiSourceReportWithNoChangesInOneReport() {
final NamedDependencyChangeReport sourceA = new NamedDependencyChangeReport("project A", REPORT);
final NamedDependencyChangeReport sourceB = new NamedDependencyChangeReport("project B", EMPTY_REPORT);
- final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(sourceA, sourceB)));
- assertThat(result, equalTo(
+ assertThat(render(sourceA, sourceB), equalTo(
"## Dependency Updates\n\n### Project A\n\n#### Compile Dependency Updates\n\n* Added `com.example:my-lib:1.2.3`"));
}
@Test
void testRenderSourceReportWithoutChanges() {
final NamedDependencyChangeReport sourceA = new NamedDependencyChangeReport("project A", EMPTY_REPORT);
- final String result = String.join("\n", new DependencyChangeReportRenderer().render(List.of(sourceA)));
- assertThat(result, emptyString());
+ final Optional result = new DependencyChangeReportRenderer().render(List.of(sourceA));
+ assertThat(result.isPresent(), is(false));
}
-}
\ No newline at end of file
+
+ private String render(final NamedDependencyChangeReport... reports) {
+ final Optional section = new DependencyChangeReportRenderer().render(asList(reports));
+ assertThat(section.isPresent(), is(true));
+ return section.get().toString();
+ }
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java
index a030479a..64ba39c5 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/LatestChangesFileValidatorTest.java
@@ -11,7 +11,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileName;
import com.exasol.projectkeeper.validators.finding.SimpleValidationFinding;
class LatestChangesFileValidatorTest {
@@ -38,8 +38,8 @@ private LatestChangesFileValidator testee(final Path tempDir, final String... ve
final Path folder = tempDir.resolve(Path.of("doc", "changes"));
Files.createDirectories(folder);
for (final String v : versions) {
- final ChangesFile.Filename cfile = new ChangesFile.Filename(v);
- Files.createFile(folder.resolve(cfile.filename()));
+ final ChangesFileName file = new ChangesFileName(v);
+ Files.createFile(folder.resolve(file.filename()));
}
return new LatestChangesFileValidator(tempDir, "2.0.0");
}
From 39575549485a2cf4d2c5f98bef3bb0585aa248cd Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 8 Feb 2024 05:29:11 +0100
Subject: [PATCH 65/78] Fix sonar warning
---
.../projectkeeper/dependencyupdate/ChangesFileUpdater.java | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java
index e8c2667e..63637e06 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java
@@ -6,11 +6,7 @@
class ChangesFileUpdater {
ChangesFile update(final ChangesFile changesFile) {
final Builder builder = changesFile.toBuilder();
- update(builder);
+ // Changes file will be updated in the next PR
return builder.build();
}
-
- private void update(final Builder builder) {
-
- }
}
From 90196d89596d8b6eb847b5fb8c7100fbb8bde16c Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 8 Feb 2024 06:30:45 +0100
Subject: [PATCH 66/78] Add unit tests for version incrementor
---
...nProjectWithProjectKeeperPluginWriter.java | 10 +-
.../plugin/ProjectKeeperMojoIT.java | 10 +-
.../ProjectVersionIncrementor.java | 39 ++----
.../sources/analyze/MavenSourceAnalyzer.java | 13 +-
.../validators/changesfile/ChangesFile.java | 2 +-
.../validators/pom/PomFileIO.java | 52 ++++++++
.../JavaProjectCrawlerRunnerIT.java | 9 +-
.../ProjectVersionIncrementorTest.java | 118 ++++++++++++++++++
.../validators/pom/PomFileValidatorTest.java | 22 ++--
9 files changed, 201 insertions(+), 74 deletions(-)
create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java
create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java
diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java
index 11953af5..0cb66aef 100644
--- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java
+++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java
@@ -1,13 +1,13 @@
package com.exasol.projectkeeper.plugin;
-import java.io.*;
import java.nio.file.Path;
import java.util.List;
import org.apache.maven.model.*;
-import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.codehaus.plexus.util.xml.Xpp3Dom;
+import com.exasol.projectkeeper.validators.pom.PomFileIO;
+
public class MvnProjectWithProjectKeeperPluginWriter {
public static final String PROJECT_ARTIFACT_ID = "my-test-project";
public static final String PROJECT_VERSION = "0.1.0";
@@ -26,11 +26,7 @@ public MvnProjectWithProjectKeeperPluginWriter(final String projectKeeperVersion
public void writeAsPomToProject(final Path projectDir) {
final Path path = projectDir.resolve("pom.xml");
- try (final FileWriter fileWriter = new FileWriter(path.toFile())) {
- new MavenXpp3Writer().write(fileWriter, this.model);
- } catch (final IOException exception) {
- throw new UncheckedIOException("Failed writing POM to file " + path, exception);
- }
+ new PomFileIO().writePom(model, path);
}
public MvnProjectWithProjectKeeperPluginWriter addDependency(final String groupId, final String artifactId,
diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java
index c7ea6a74..bf7c63ad 100644
--- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java
+++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/ProjectKeeperMojoIT.java
@@ -19,8 +19,6 @@
import org.apache.maven.it.VerificationException;
import org.apache.maven.it.Verifier;
import org.apache.maven.model.Model;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.hamcrest.Matcher;
@@ -31,6 +29,7 @@
import com.exasol.mavenpluginintegrationtesting.MavenIntegrationTestEnvironment;
import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
+import com.exasol.projectkeeper.validators.pom.PomFileIO;
class ProjectKeeperMojoIT {
private static final String ORIGINAL_SLF4J_VERSION = "1.7.36";
@@ -138,12 +137,7 @@ private void updateReleaseDate(final String changeLogVersion, final String newRe
}
private Model readPom() {
- final Path path = projectDir.resolve("pom.xml");
- try {
- return new MavenXpp3Reader().read(Files.newBufferedReader(path));
- } catch (IOException | XmlPullParserException exception) {
- throw new IllegalStateException("failed to parse " + path + ": " + exception.getMessage(), exception);
- }
+ return new PomFileIO().readPom(projectDir.resolve("pom.xml"));
}
@ParameterizedTest
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
index 95f2f383..a9013644 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
@@ -2,18 +2,12 @@
import static com.exasol.projectkeeper.shared.config.ProjectKeeperModule.JAR_ARTIFACT;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.nio.file.Files;
import java.nio.file.Path;
import java.time.*;
import java.util.Objects;
import java.util.Optional;
import org.apache.maven.model.Model;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
-import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import com.exasol.errorreporting.ExaError;
import com.exasol.projectkeeper.Logger;
@@ -21,6 +15,7 @@
import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder;
import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO;
+import com.exasol.projectkeeper.validators.pom.PomFileIO;
import com.vdurmont.semver4j.Semver;
class ProjectVersionIncrementor {
@@ -31,18 +26,22 @@ class ProjectVersionIncrementor {
private final Clock clock;
private final Path projectDir;
private final Logger logger;
+ private final PomFileIO pomFileIO;
ProjectVersionIncrementor(final ProjectKeeperConfig config, final Logger logger, final Path projectDir,
final String currentProjectVersion) {
- this(config, logger, projectDir, currentProjectVersion, new ChangesFileIO(), Clock.systemUTC());
+ this(config, logger, projectDir, currentProjectVersion, new ChangesFileIO(), new PomFileIO(),
+ Clock.systemUTC());
}
ProjectVersionIncrementor(final ProjectKeeperConfig config, final Logger logger, final Path projectDir,
- final String currentProjectVersion, final ChangesFileIO changesFileIO, final Clock clock) {
+ final String currentProjectVersion, final ChangesFileIO changesFileIO, final PomFileIO pomFileIO,
+ final Clock clock) {
this.config = config;
this.logger = logger;
this.projectDir = projectDir;
this.changesFileIO = changesFileIO;
+ this.pomFileIO = pomFileIO;
this.clock = clock;
this.currentProjectVersion = Objects.requireNonNull(currentProjectVersion, "currentProjectVersion");
}
@@ -75,11 +74,12 @@ private LocalDate today() {
}
String incrementProjectVersion() {
- final Model pom = readPom();
+ final Path path = getPomPath();
+ final Model pom = pomFileIO.readPom(path);
if (!this.currentProjectVersion.equals(pom.getVersion())) {
throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-174").message(
- "Inconsistent project version {{version in pom file}} found in pom {{pom file path}}, expected {{expected version}}",
- pom.getVersion(), pom.getPomFile(), currentProjectVersion).ticketMitigation().toString());
+ "Inconsistent project version {{version in pom file}} found in pom {{pom file path}}, expected {{expected version}}.",
+ pom.getVersion(), path, currentProjectVersion).ticketMitigation().toString());
}
final String nextVersion = incrementVersion(pom);
if (usesReferenceCheckerPlugin()) {
@@ -112,24 +112,9 @@ static String getIncrementedVersion(final String version) {
return current.nextPatch().toString();
}
- private Model readPom() {
- final Path path = getPomPath();
- try {
- return new MavenXpp3Reader().read(Files.newBufferedReader(path));
- } catch (IOException | XmlPullParserException exception) {
- throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-172")
- .message("Failed to read pom {{pom file path}}", path).toString(), exception);
- }
- }
-
private void writePom(final Model pom) {
final Path path = getPomPath();
- try {
- new MavenXpp3Writer().write(Files.newOutputStream(path), pom);
- } catch (final IOException exception) {
- throw new UncheckedIOException(ExaError.messageBuilder("E-PK-CORE-173")
- .message("Failed to write pom {{pom file path}}", path).toString(), exception);
- }
+ pomFileIO.writePom(pom, path);
}
private Path getPomPath() {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java
index f02e8ff9..1f550b76 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java
@@ -3,7 +3,6 @@
import static com.exasol.projectkeeper.shared.config.SourceType.MAVEN;
import static java.util.Collections.emptyMap;
-import java.io.FileInputStream;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.List;
@@ -11,7 +10,6 @@
import java.util.stream.Collectors;
import org.apache.maven.model.Model;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import com.exasol.errorreporting.ExaError;
import com.exasol.projectkeeper.JavaProjectCrawlerRunner;
@@ -19,6 +17,7 @@
import com.exasol.projectkeeper.shared.mavenprojectcrawler.CrawledMavenProject;
import com.exasol.projectkeeper.sources.AnalyzedMavenSource;
import com.exasol.projectkeeper.sources.AnalyzedSource;
+import com.exasol.projectkeeper.validators.pom.PomFileIO;
/**
* This class analyzes Java Maven projects.
@@ -106,14 +105,6 @@ private CrawledMavenProject getCrawlResultForProject(final Source source,
}
private Model readMavenModel(final Source source) {
- try (final FileInputStream fileInputStream = new FileInputStream(source.getPath().toFile())) {
- return new MavenXpp3Reader().read(fileInputStream);
- } catch (final Exception exception) {
- // Catch Exception instead of org.codehaus.plexus.util.xml.pull.XmlPullParserException helps avoid adding
- // runtime dependency org.codehaus.plexus:plexus-utils
- throw new IllegalStateException(
- ExaError.messageBuilder("E-PK-CORE-94").message("Failed to analyze maven source.").toString(),
- exception);
- }
+ return new PomFileIO().readPom(source.getPath());
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
index b6e1020b..6e04e2f0 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
@@ -109,7 +109,7 @@ public String getCodeName() {
*/
public Optional getParsedReleaseDate() {
try {
- return Optional.of(LocalDate.parse(this.getReleaseDate()));
+ return Optional.ofNullable(this.getReleaseDate()).map(LocalDate::parse);
} catch (final DateTimeParseException exception) {
return Optional.empty();
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java
new file mode 100644
index 00000000..9560b2fb
--- /dev/null
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java
@@ -0,0 +1,52 @@
+package com.exasol.projectkeeper.validators.pom;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+import com.exasol.errorreporting.ExaError;
+
+/**
+ * This class reads and writes POM files.
+ */
+public class PomFileIO {
+
+ private static final MavenXpp3Writer WRITER = new MavenXpp3Writer();
+ private static final MavenXpp3Reader READER = new MavenXpp3Reader();
+
+ /**
+ * Read the given file and parse it as a POM file.
+ *
+ * @param path path to read
+ * @return parsed POM model
+ */
+ public Model readPom(final Path path) {
+ try {
+ return READER.read(Files.newBufferedReader(path));
+ } catch (IOException | XmlPullParserException exception) {
+ throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-172")
+ .message("Failed to read pom {{pom file path}}", path).toString(), exception);
+ }
+ }
+
+ /**
+ * Write a POM model to a file
+ *
+ * @param model the POM model to write
+ * @param path the path to write
+ */
+ public void writePom(final Model model, final Path path) {
+ try {
+ WRITER.write(Files.newOutputStream(path), model);
+ } catch (final IOException exception) {
+ throw new UncheckedIOException(ExaError.messageBuilder("E-PK-CORE-173")
+ .message("Failed to write pom {{pom file path}}", path).toString(), exception);
+ }
+ }
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
index ea11a2c7..0432ec36 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
@@ -6,12 +6,10 @@
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertThrows;
-import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
-import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.hamcrest.Matchers;
@@ -26,6 +24,7 @@
import com.exasol.projectkeeper.shared.mavenprojectcrawler.CrawledMavenProject;
import com.exasol.projectkeeper.shared.mavenprojectcrawler.MavenProjectCrawlResult;
import com.exasol.projectkeeper.test.TestMavenModel;
+import com.exasol.projectkeeper.validators.pom.PomFileIO;
@Tag("integration")
class JavaProjectCrawlerRunnerIT {
@@ -83,11 +82,9 @@ void testGetDependencyChangesFailsForMissingPom() throws GitAPIException, IOExce
allOf(containsString("[FATAL] Non-readable POM"), containsString(missingPomFile.toString())));
}
- private void writePomFile(final Path pomFile) throws IOException {
+ private void writePomFile(final Path pomFile) {
final TestMavenModel model = new TestMavenModel();
model.addDependency(DEPENDENCY_ID, DEPENDENCY_GROUP, "", DEPENDENCY_VERSION);
- try (final FileWriter fileWriter = new FileWriter(pomFile.toFile())) {
- new MavenXpp3Writer().write(fileWriter, model);
- }
+ new PomFileIO().writePom(model, pomFile);
}
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java
new file mode 100644
index 00000000..c41de2c0
--- /dev/null
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java
@@ -0,0 +1,118 @@
+package com.exasol.projectkeeper.dependencyupdate;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.nio.file.Path;
+import java.time.*;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.model.Model;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import com.exasol.projectkeeper.Logger;
+import com.exasol.projectkeeper.shared.config.*;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO;
+import com.exasol.projectkeeper.validators.pom.PomFileIO;
+
+@ExtendWith(MockitoExtension.class)
+class ProjectVersionIncrementorTest {
+
+ private static final Instant NOW = Instant.parse("2007-12-03T10:15:30.00Z");
+ private static final Path PROJECT_DIR = Path.of("ProjectDir");
+ private static final Path POM_PATH = PROJECT_DIR.resolve("pom.xml");
+ private static final String CURRENT_PROJECT_VERSION = "1.2.3";
+ private static final Clock fixedClock = Clock.fixed(NOW, ZoneId.of("CET"));
+
+ @Mock
+ private Logger loggerMock;
+ @Mock
+ private ChangesFileIO changesFileIOMock;
+ @Mock
+ private PomFileIO pomFileIOMock;
+
+ @ParameterizedTest
+ @CsvSource(nullValues = "NULL", value = { "NULL, false", "invalid data, false", "2007-??-??, false",
+ "2024-??-??, false", "2007-01-01, true", "2007-12-02, true", "2007-12-03, false", "2007-12-04, false",
+ "2024-02-08, false" })
+ void isCurrentVersionReleased(final String releaseDate, final boolean expectedReleaseState) {
+ final ChangesFile changesFile = ChangesFile.builder().releaseDate(releaseDate).build();
+ when(changesFileIOMock.read(PROJECT_DIR.resolve("doc/changes/changes_1.2.3.md"))).thenReturn(changesFile);
+ assertThat("release date '" + releaseDate + "' is considered as " + (expectedReleaseState ? "" : "not ")
+ + "released", testee().isCurrentVersionReleased(), is(expectedReleaseState));
+ }
+
+ @Test
+ void incrementProjectVersionFailsForInconsistentVersionInPom() {
+ final Model pomModel = new Model();
+ pomModel.setVersion("1.2.2");
+ when(pomFileIOMock.readPom(POM_PATH)).thenReturn(pomModel);
+ final ProjectVersionIncrementor testee = testee(configWithoutJarArtifact());
+
+ final IllegalStateException exception = assertThrows(IllegalStateException.class,
+ testee::incrementProjectVersion);
+ assertThat(exception.getMessage(), startsWith(
+ "E-PK-CORE-174: Inconsistent project version '1.2.2' found in pom 'ProjectDir/pom.xml', expected '1.2.3'."));
+ }
+
+ @ParameterizedTest
+ @CsvSource({ "0.0.0, 0.0.1", "0.1.1, 0.1.2", "1.2.1, 1.2.2", "9.9.9, 9.9.10", "1.2.99, 1.2.100",
+ "99.34.12345, 99.34.12346" })
+ void incrementProjectVersion(final String currentVersion, final String expectedNextVersion) {
+ final Model pomModel = new Model();
+ pomModel.setVersion(currentVersion);
+ when(pomFileIOMock.readPom(POM_PATH)).thenReturn(pomModel);
+ final String newVersion = testee(configWithoutJarArtifact(), currentVersion).incrementProjectVersion();
+ assertAll(() -> assertThat(newVersion, equalTo(expectedNextVersion)),
+ () -> assertThat(pomModel.getVersion(), equalTo(newVersion)));
+ verify(pomFileIOMock).writePom(same(pomModel), eq(POM_PATH));
+ }
+
+ @Test
+ void incrementProjectVersionWithJarArtifactTriesToUpdateReferences() {
+ final Model pomModel = new Model();
+ pomModel.setVersion(CURRENT_PROJECT_VERSION);
+ when(pomFileIOMock.readPom(POM_PATH)).thenReturn(pomModel);
+ final ProjectVersionIncrementor testee = testee(configWithJarArtifact());
+ // This fails because the project dir does not exist when we try to run reference checker.
+ final IllegalStateException exception = assertThrows(IllegalStateException.class,
+ testee::incrementProjectVersion);
+ assertThat(exception.getMessage(), startsWith(
+ "E-PK-CORE-125: Error executing command 'mvn --batch-mode artifact-reference-checker:unify'."));
+ }
+
+ private ProjectVersionIncrementor testee() {
+ return testee(null);
+ }
+
+ private ProjectVersionIncrementor testee(final ProjectKeeperConfig config) {
+ return testee(config, CURRENT_PROJECT_VERSION);
+ }
+
+ private ProjectVersionIncrementor testee(final ProjectKeeperConfig config, final String currentProjectVersion) {
+ return new ProjectVersionIncrementor(config, loggerMock, PROJECT_DIR, currentProjectVersion, changesFileIOMock,
+ pomFileIOMock, fixedClock);
+ }
+
+ private ProjectKeeperConfig configWithJarArtifact() {
+ return ProjectKeeperConfig.builder()
+ .sources(List.of(Source.builder().modules(Set.of(ProjectKeeperModule.JAR_ARTIFACT)).build())).build();
+ }
+
+ private ProjectKeeperConfig configWithoutJarArtifact() {
+ return ProjectKeeperConfig.builder().sources(List.of(Source.builder().modules(Set.of()).build())).build();
+ }
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java
index 7bffedf2..e3b32bf5 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java
@@ -8,7 +8,6 @@
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.mockito.Mockito.mock;
-import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -16,7 +15,6 @@
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
@@ -115,33 +113,29 @@ private void runFix(final ParentPomRef parentPomRef) {
}
@Test
- void testMissingVersion() throws IOException {
+ void testMissingVersion() {
getTestModel().withVersion(null).writeAsPomToProject(this.tempDir);
assertThat(runValidator(null),
hasFindingWithMessageMatchingRegex("(?s)E-PK-CORE-111: Failed to detect project version.*"));
}
@Test
- void testMissingVersionButParentPomRef() throws IOException, XmlPullParserException {
+ void testMissingVersionButParentPomRef() {
getTestModel().withVersion(null).withParentVersion("2.3.4").writeAsPomToProject(this.tempDir);
runFix(new ParentPomRef("com.example", "my-parent", "1.2.3", null));
- try (final FileReader reader = new FileReader(this.tempDir.resolve("pk_generated_parent.pom").toFile())) {
- final Model pom = new MavenXpp3Reader().read(reader);
- assertThat(pom.getVersion(), equalTo("1.2.3"));
- }
+ final Model pom = new PomFileIO().readPom(this.tempDir.resolve("pk_generated_parent.pom"));
+ assertThat(pom.getVersion(), equalTo("1.2.3"));
}
@Test
- void testMissingVersionButFromParent() throws IOException, XmlPullParserException {
+ void testMissingVersionButFromParent() {
getTestModel().withVersion(null).withParentVersion("2.3.4").writeAsPomToProject(this.tempDir);
assertThat(runValidator(null),
not(hasFindingWithMessageMatchingRegex("(?s)E-PK-CORE-111: Failed to detect project version.*")));
}
- private Model readModel(final Path projectDir) throws XmlPullParserException, IOException {
- try (final FileReader fileReader = new FileReader(projectDir.toFile())) {
- return new MavenXpp3Reader().read(fileReader);
- }
+ private Model readModel(final Path projectDir) {
+ return new PomFileIO().readPom(projectDir);
}
@Test
@@ -279,4 +273,4 @@ void testValidAfterFix() throws IOException {
assertThat(result, empty());
}
-}
\ No newline at end of file
+}
From e47066671d9fdd5e72d5673e3c9f1cf0a1eede6f Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 8 Feb 2024 07:27:25 +0100
Subject: [PATCH 67/78] Use command executor
---
.../JavaProjectCrawlerRunner.java | 11 ++---
.../dependencyupdate/DependencyUpdater.java | 14 ++++--
.../ProjectVersionIncrementor.java | 13 +++--
.../analyze/generic/CommandExecutor.java | 19 +++++--
.../analyze/generic/MavenProcessBuilder.java | 28 ++++++++---
.../analyze/generic/ProcessResult.java | 38 ++++++++++++++
.../sources/analyze/generic/ShellCommand.java | 30 +++++++++++-
.../analyze/generic/SimpleProcess.java | 9 ++++
.../sources/analyze/golang/GoBinary.java | 2 +-
.../analyze/golang/GolangServices.java | 10 ++--
.../sources/analyze/npm/NpmServices.java | 2 +-
.../DependencyUpdaterTest.java | 49 +++++++++++++++++++
.../ProjectVersionIncrementorTest.java | 26 +++++++---
.../sources/analyze/golang/GoBinaryTest.java | 4 +-
.../sources/analyze/npm/NpmServicesTest.java | 28 ++++++-----
15 files changed, 226 insertions(+), 57 deletions(-)
create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java
create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java
index 18dcf1ed..b419defa 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java
@@ -8,8 +8,7 @@
import com.exasol.projectkeeper.shared.mavenprojectcrawler.MavenProjectCrawlResult;
import com.exasol.projectkeeper.shared.mavenprojectcrawler.ResponseCoder;
-import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder;
-import com.exasol.projectkeeper.sources.analyze.generic.SimpleProcess;
+import com.exasol.projectkeeper.sources.analyze.generic.*;
/**
* Runs the maven plugin goal on the current repository and returns the parsed result.
@@ -43,9 +42,8 @@ public MavenProjectCrawlResult crawlProject(final Path... pomFiles) {
private String runCrawlerPlugin(final Path... pomFiles) {
final MavenProcessBuilder builder = buildMavenCommand(pomFiles);
- final SimpleProcess process = builder.startSimpleProcess();
- process.waitUntilFinished(Duration.ofSeconds(90));
- return new ResponseCoder().decodeResponse(process.getOutputStreamContent());
+ final ProcessResult result = new CommandExecutor().execute(builder.buildCommand());
+ return new ResponseCoder().decodeResponse(result.getOutputStreamContent());
}
private MavenProcessBuilder buildMavenCommand(final Path... pomFiles) {
@@ -60,7 +58,8 @@ private MavenProcessBuilder buildMavenCommand(final Path... pomFiles) {
* comparing dependencies).
*/
"-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true")
- .workingDir(null);
+ .workingDir(null) //
+ .timeout(Duration.ofSeconds(90));
if (this.mvnRepositoryOverride != null) {
builder.addArgument("-Dmaven.repo.local=" + this.mvnRepositoryOverride);
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
index aec19dd7..224d0cb6 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
@@ -7,7 +7,7 @@
import com.exasol.projectkeeper.Logger;
import com.exasol.projectkeeper.ProjectKeeper;
import com.exasol.projectkeeper.shared.config.ProjectKeeperConfig;
-import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder;
+import com.exasol.projectkeeper.sources.analyze.generic.*;
import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO;
@@ -24,10 +24,12 @@ public class DependencyUpdater {
private final ChangesFileIO changesFileIO;
private final String currentProjectVersion;
private final ChangesFileUpdater changesFileUpdater;
+ private final CommandExecutor commandExecutor;
DependencyUpdater(final ProjectKeeper projectKeeper, final Logger logger, final Path projectDir,
final String currentProjectVersion, final ProjectVersionIncrementor projectVersionIncrementor,
- final ChangesFileIO changesFileIO, final ChangesFileUpdater changesFileUpdater) {
+ final ChangesFileIO changesFileIO, final ChangesFileUpdater changesFileUpdater,
+ final CommandExecutor commandExecutor) {
this.projectKeeper = projectKeeper;
this.logger = logger;
this.projectDir = projectDir;
@@ -35,6 +37,7 @@ public class DependencyUpdater {
this.projectVersionIncrementor = projectVersionIncrementor;
this.changesFileIO = changesFileIO;
this.changesFileUpdater = changesFileUpdater;
+ this.commandExecutor = commandExecutor;
}
/**
@@ -51,7 +54,7 @@ public static DependencyUpdater create(final ProjectKeeper projectKeeper, final
final Logger logger, final Path projectDir, final String currentProjectVersion) {
return new DependencyUpdater(projectKeeper, logger, projectDir, currentProjectVersion,
new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion), new ChangesFileIO(),
- new ChangesFileUpdater());
+ new ChangesFileUpdater(), new CommandExecutor());
}
/**
@@ -89,8 +92,9 @@ private void updateDependencyVersions() {
}
private void runMaven(final String mavenGoal) {
- MavenProcessBuilder.create().addArgument(mavenGoal).workingDir(projectDir).startSimpleProcess()
- .waitUntilFinished(MAVEN_COMMAND_TIMEOUT);
+ final ShellCommand command = MavenProcessBuilder.create().addArgument(mavenGoal).workingDir(projectDir)
+ .timeout(MAVEN_COMMAND_TIMEOUT).buildCommand();
+ commandExecutor.execute(command);
}
private void runProjectKeeperFix() {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
index a9013644..3fe8ac8b 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
@@ -12,7 +12,7 @@
import com.exasol.errorreporting.ExaError;
import com.exasol.projectkeeper.Logger;
import com.exasol.projectkeeper.shared.config.ProjectKeeperConfig;
-import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder;
+import com.exasol.projectkeeper.sources.analyze.generic.*;
import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO;
import com.exasol.projectkeeper.validators.pom.PomFileIO;
@@ -27,21 +27,23 @@ class ProjectVersionIncrementor {
private final Path projectDir;
private final Logger logger;
private final PomFileIO pomFileIO;
+ private final CommandExecutor commandExecutor;
ProjectVersionIncrementor(final ProjectKeeperConfig config, final Logger logger, final Path projectDir,
final String currentProjectVersion) {
this(config, logger, projectDir, currentProjectVersion, new ChangesFileIO(), new PomFileIO(),
- Clock.systemUTC());
+ new CommandExecutor(), Clock.systemUTC());
}
ProjectVersionIncrementor(final ProjectKeeperConfig config, final Logger logger, final Path projectDir,
final String currentProjectVersion, final ChangesFileIO changesFileIO, final PomFileIO pomFileIO,
- final Clock clock) {
+ final CommandExecutor commandExecutor, final Clock clock) {
this.config = config;
this.logger = logger;
this.projectDir = projectDir;
this.changesFileIO = changesFileIO;
this.pomFileIO = pomFileIO;
+ this.commandExecutor = commandExecutor;
this.clock = clock;
this.currentProjectVersion = Objects.requireNonNull(currentProjectVersion, "currentProjectVersion");
}
@@ -94,8 +96,9 @@ private boolean usesReferenceCheckerPlugin() {
private void updateReferences() {
logger.info("Unify artifact references");
- MavenProcessBuilder.create().addArgument("artifact-reference-checker:unify").workingDir(projectDir)
- .startSimpleProcess().waitUntilFinished(Duration.ofSeconds(30));
+ final ShellCommand command = MavenProcessBuilder.create().addArgument("artifact-reference-checker:unify")
+ .workingDir(projectDir).timeout(Duration.ofSeconds(30)).buildCommand();
+ commandExecutor.execute(command);
}
private String incrementVersion(final Model pom) {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java
index c6410a73..bd8f3aea 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java
@@ -8,16 +8,27 @@
public class CommandExecutor {
/**
- * Executes the specified {@link ShellCommand}
+ * Executes the specified {@link ShellCommand}.
*
* @param sc command to execute
* @param workingDirectory directory to run the execution in
- * @return standard output of the command
+ * @return standard and error output of the command
* @throws IllegalStateException if execution fails.
*/
- public String execute(final ShellCommand sc, final Path workingDirectory) throws IllegalStateException {
+ public ProcessResult execute(final ShellCommand sc, final Path workingDirectory) throws IllegalStateException {
final SimpleProcess process = SimpleProcess.start(workingDirectory, sc.commandline());
process.waitUntilFinished(sc.timeout());
- return process.getOutputStreamContent();
+ return process.getResult();
+ }
+
+ /**
+ * Executes the specified {@link ShellCommand}.
+ *
+ * @param sc command to execute
+ * @return standard and error output of the command
+ * @throws IllegalStateException if execution fails.
+ */
+ public ProcessResult execute(final ShellCommand sc) throws IllegalStateException {
+ return execute(sc, sc.workingDir().orElse(null));
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
index 56a0cf28..0e002cbb 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
@@ -3,6 +3,7 @@
import static java.util.Arrays.asList;
import java.nio.file.Path;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@@ -13,8 +14,9 @@
* This class allows building and starting a {@code mvn} command.
*/
public class MavenProcessBuilder {
- private final List command = new ArrayList<>();
+ private final List args = new ArrayList<>();
private Path workingDir = null;
+ private Duration timeout = null;
private MavenProcessBuilder() {
// Use create() method
@@ -27,7 +29,6 @@ private MavenProcessBuilder() {
*/
public static MavenProcessBuilder create() {
final MavenProcessBuilder builder = new MavenProcessBuilder();
- builder.addArgument(getMavenExecutable());
builder.addArgument("--batch-mode");
return builder;
}
@@ -39,7 +40,7 @@ public static MavenProcessBuilder create() {
* @return {@code this} for fluent programming
*/
public MavenProcessBuilder addArguments(final String... arguments) {
- command.addAll(asList(arguments));
+ args.addAll(asList(arguments));
return this;
}
@@ -50,7 +51,7 @@ public MavenProcessBuilder addArguments(final String... arguments) {
* @return {@code this} for fluent programming
*/
public MavenProcessBuilder addArgument(final String argument) {
- command.add(argument);
+ args.add(argument);
return this;
}
@@ -66,12 +67,23 @@ public MavenProcessBuilder workingDir(final Path workingDir) {
}
/**
- * Build the command and run it.
+ * Set the timeout for running the process.
*
- * @return the running {@link SimpleProcess}
+ * @param timeout process timeout
+ * @return {@code this} for fluent programming
+ */
+ public MavenProcessBuilder timeout(final Duration timeout) {
+ this.timeout = timeout;
+ return this;
+ }
+
+ /**
+ * Build a {@link ShellCommand} that can be started with {@link CommandExecutor}.
+ *
+ * @return the built command
*/
- public SimpleProcess startSimpleProcess() {
- return SimpleProcess.start(workingDir, command);
+ public ShellCommand buildCommand() {
+ return ShellCommand.builder().command(getMavenExecutable()).args(this.args).timeout(this.timeout).build();
}
private static String getMavenExecutable() {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java
new file mode 100644
index 00000000..baf30819
--- /dev/null
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java
@@ -0,0 +1,38 @@
+package com.exasol.projectkeeper.sources.analyze.generic;
+
+/**
+ * Result of executing a process.
+ */
+public class ProcessResult {
+ private final String outputStreamContent;
+ private final String errorStreamContent;
+
+ /**
+ * Create a new process result.
+ *
+ * @param outputStreamContent output stream content
+ * @param errorStreamContent error stream content
+ */
+ public ProcessResult(final String outputStreamContent, final String errorStreamContent) {
+ this.outputStreamContent = outputStreamContent;
+ this.errorStreamContent = errorStreamContent;
+ }
+
+ /**
+ * Content of the output stream.
+ *
+ * @return output stream
+ */
+ public String getOutputStreamContent() {
+ return outputStreamContent;
+ }
+
+ /**
+ * Content of the error stream.
+ *
+ * @return error stream
+ */
+ public String getErrorStreamContent() {
+ return errorStreamContent;
+ }
+}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java
index 076d1488..c69471d8 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java
@@ -1,5 +1,6 @@
package com.exasol.projectkeeper.sources.analyze.generic;
+import java.nio.file.Path;
import java.time.Duration;
import java.util.*;
import java.util.logging.Logger;
@@ -22,6 +23,7 @@ public static Builder builder() {
private Duration timeout;
private String mainCommand;
private String subCommand;
+ private Path workingDir = null;
private final List options = new ArrayList<>();
/**
@@ -52,6 +54,15 @@ public Duration timeout() {
return this.timeout;
}
+ /**
+ * Working directory for the process.
+ *
+ * @return working dir
+ */
+ public Optional workingDir() {
+ return Optional.ofNullable(this.workingDir);
+ }
+
/**
* Builder for a new instance of {@link ShellCommand}.
*/
@@ -67,6 +78,15 @@ public Builder timeout(final Duration timeout) {
return this;
}
+ /**
+ * @param workingDir optional working directory for the process
+ * @return this for fluent programming
+ */
+ public Builder workingDir(final Path workingDir) {
+ this.shellCommand.workingDir = workingDir;
+ return this;
+ }
+
/**
* @param command name of the command to execute. On Windows platform probably with a suffix like ".exe" or
* ".cmd", see {@link OsCheck#suffix}
@@ -94,7 +114,15 @@ public Builder command(final String main, final String sub) {
* @return this for fluent programming
*/
public Builder args(final String... value) {
- this.shellCommand.options.addAll(Arrays.asList(value));
+ return this.args(Arrays.asList(value));
+ }
+
+ /**
+ * @param value additional options and arguments to the command
+ * @return this for fluent programming
+ */
+ public Builder args(final List value) {
+ this.shellCommand.options.addAll(value);
return this;
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java
index cf1903a3..a07fe90c 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java
@@ -129,6 +129,15 @@ public String getErrorStreamContent() {
}
}
+ /**
+ * Get the process result containing output and error stream content.
+ *
+ * @return result
+ */
+ public ProcessResult getResult() {
+ return new ProcessResult(getOutputStreamContent(), getErrorStreamContent());
+ }
+
private void waitForExecutionFinished(final Duration executionTimeout) {
try {
if (!this.process.waitFor(executionTimeout.toMillis(), TimeUnit.MILLISECONDS)) {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java
index 40f22564..b4c8caa7 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java
@@ -63,7 +63,7 @@ public GoBinary install() {
.args("install", this.moduleName) //
.build();
try {
- this.executor.execute(shellCommand, null);
+ this.executor.execute(shellCommand);
} catch (final IllegalStateException exception) {
throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-161")
.message("Error installing go binary {{binary}}.", this.binaryName).toString(), exception);
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java
index 443814d3..aad86426 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java
@@ -78,9 +78,9 @@ private String retrieveLicenses(final Path absoluteSourcePath, final String modu
.timeout(EXECUTION_TIMEOUT) //
.command(goLicenses.command()) //
.args("csv", module) //
- .build();
+ .workingDir(absoluteSourcePath).build();
try {
- return this.executor.execute(shellCommand, absoluteSourcePath);
+ return this.executor.execute(shellCommand).getOutputStreamContent();
} catch (final RuntimeException exception) {
throw new IllegalStateException(
ExaError.messageBuilder("E-PK-CORE-142")
@@ -100,8 +100,9 @@ Path getModuleDir(final Path absoluteSourcePath, final String moduleName) {
.timeout(Duration.ofSeconds(3)) //
.command(GoBinary.GO.command()) //
.args("list", "-m", "-f", "{{.Dir}}", moduleName) //
+ .workingDir(absoluteSourcePath) //
.build();
- final String output = this.executor.execute(shellCommand, absoluteSourcePath).trim();
+ final String output = this.executor.execute(shellCommand).getOutputStreamContent().trim();
if (output.isEmpty()) {
throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-160")
.message("Did not get directory for module {{module name}}.", moduleName).ticketMitigation()
@@ -226,7 +227,8 @@ void installDependencies(final Path projectPath) {
.timeout(Duration.ofMinutes(2)) //
.command(GoBinary.GO.command()) //
.args("get", "-t", "./...") //
+ .workingDir(projectPath) //
.build();
- this.executor.execute(sc, projectPath);
+ this.executor.execute(sc);
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java
index 1128a165..ac1d9755 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java
@@ -72,7 +72,7 @@ JsonObject getLicenses(final Path folder) {
private JsonObject getJsonOutput(final ShellCommand cmd, final Path workingDir) {
fetchDependencies(workingDir);
- final String stdout = this.executor.execute(cmd, workingDir);
+ final String stdout = this.executor.execute(cmd, workingDir).getOutputStreamContent();
return JsonIo.read(new StringReader(stdout));
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java
new file mode 100644
index 00000000..27090fdd
--- /dev/null
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java
@@ -0,0 +1,49 @@
+package com.exasol.projectkeeper.dependencyupdate;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import java.nio.file.Path;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import com.exasol.projectkeeper.Logger;
+import com.exasol.projectkeeper.ProjectKeeper;
+import com.exasol.projectkeeper.sources.analyze.generic.CommandExecutor;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO;
+
+@ExtendWith(MockitoExtension.class)
+class DependencyUpdaterTest {
+
+ private static final Path PROJECT_DIR = Path.of("ProjectDir");
+ private static final String CURRENT_PROJECT_VERSION = "1.2.3";
+ @Mock
+ private ProjectKeeper projectKeeperMock;
+ @Mock
+ private Logger loggerMock;
+ @Mock
+ private ProjectVersionIncrementor projectVersionIncrementorMock;
+ @Mock
+ private ChangesFileIO changesFileIOMock;
+ @Mock
+ private ChangesFileUpdater changesFileUpdaterMock;
+ @Mock
+ private CommandExecutor commandExecutorMock;
+
+ @Test
+ void updateDependencies() {
+ // assertUpdate();
+ }
+
+ private DependencyUpdater testee() {
+ return new DependencyUpdater(projectKeeperMock, loggerMock, PROJECT_DIR, CURRENT_PROJECT_VERSION,
+ projectVersionIncrementorMock, changesFileIOMock, changesFileUpdaterMock, commandExecutorMock);
+ }
+
+ private void assertUpdate() {
+ assertThat(testee().updateDependencies(), is(true));
+ }
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java
index c41de2c0..5a9432ec 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java
@@ -19,11 +19,14 @@
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import com.exasol.projectkeeper.Logger;
import com.exasol.projectkeeper.shared.config.*;
+import com.exasol.projectkeeper.sources.analyze.generic.CommandExecutor;
+import com.exasol.projectkeeper.sources.analyze.generic.ShellCommand;
import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO;
import com.exasol.projectkeeper.validators.pom.PomFileIO;
@@ -43,6 +46,8 @@ class ProjectVersionIncrementorTest {
private ChangesFileIO changesFileIOMock;
@Mock
private PomFileIO pomFileIOMock;
+ @Mock
+ private CommandExecutor commandExecutorMock;
@ParameterizedTest
@CsvSource(nullValues = "NULL", value = { "NULL, false", "invalid data, false", "2007-??-??, false",
@@ -82,16 +87,21 @@ void incrementProjectVersion(final String currentVersion, final String expectedN
}
@Test
- void incrementProjectVersionWithJarArtifactTriesToUpdateReferences() {
+ void incrementProjectVersionWithJarArtifactUpdatesReferences() {
final Model pomModel = new Model();
pomModel.setVersion(CURRENT_PROJECT_VERSION);
when(pomFileIOMock.readPom(POM_PATH)).thenReturn(pomModel);
- final ProjectVersionIncrementor testee = testee(configWithJarArtifact());
- // This fails because the project dir does not exist when we try to run reference checker.
- final IllegalStateException exception = assertThrows(IllegalStateException.class,
- testee::incrementProjectVersion);
- assertThat(exception.getMessage(), startsWith(
- "E-PK-CORE-125: Error executing command 'mvn --batch-mode artifact-reference-checker:unify'."));
+ final String newVersion = testee(configWithJarArtifact(), CURRENT_PROJECT_VERSION).incrementProjectVersion();
+ assertAll(() -> assertThat(newVersion, equalTo("1.2.4")),
+ () -> assertThat(pomModel.getVersion(), equalTo(newVersion)),
+ () -> assertThat(getExecutedCommand().commandline(), contains(startsWith("mvn"),
+ equalTo("--batch-mode"), equalTo("artifact-reference-checker:unify"))));
+ }
+
+ private ShellCommand getExecutedCommand() {
+ final ArgumentCaptor arg = ArgumentCaptor.forClass(ShellCommand.class);
+ verify(commandExecutorMock).execute(arg.capture());
+ return arg.getValue();
}
private ProjectVersionIncrementor testee() {
@@ -104,7 +114,7 @@ private ProjectVersionIncrementor testee(final ProjectKeeperConfig config) {
private ProjectVersionIncrementor testee(final ProjectKeeperConfig config, final String currentProjectVersion) {
return new ProjectVersionIncrementor(config, loggerMock, PROJECT_DIR, currentProjectVersion, changesFileIOMock,
- pomFileIOMock, fixedClock);
+ pomFileIOMock, commandExecutorMock, fixedClock);
}
private ProjectKeeperConfig configWithJarArtifact() {
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java
index 94cb90a8..5a47f174 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java
@@ -46,7 +46,7 @@ void goItself() {
@Test
void installFailure() {
- when(this.executor.execute(any(), any())).thenThrow(new IllegalStateException("bla bla"));
+ when(this.executor.execute(any())).thenThrow(new IllegalStateException("bla bla"));
final GoBinary testee = testee();
final Exception e = assertThrows(IllegalStateException.class, () -> testee.install());
assertThat(e.getMessage(), Matchers.startsWith("E-PK-CORE-161: Error installing go binary"));
@@ -56,7 +56,7 @@ void installFailure() {
@Test
void installSuccess() {
testee().install();
- verify(this.executor).execute(any(), any());
+ verify(this.executor).execute(any());
}
@Test
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java
index d892d412..b6270772 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java
@@ -22,8 +22,7 @@
import com.exasol.projectkeeper.shared.dependencies.ProjectDependencies;
import com.exasol.projectkeeper.shared.repository.GitRepository;
import com.exasol.projectkeeper.shared.repository.TaggedCommit;
-import com.exasol.projectkeeper.sources.analyze.generic.CommandExecutor;
-import com.exasol.projectkeeper.sources.analyze.generic.GitService;
+import com.exasol.projectkeeper.sources.analyze.generic.*;
@ExtendWith(MockitoExtension.class)
class NpmServicesTest {
@@ -40,9 +39,10 @@ class NpmServicesTest {
@Test
void getDependencies() {
- when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn("");
- when(this.executor.execute(eq(LIST_DEPENDENCIES), any())).thenReturn(TestData.DEPENDENCIES);
- when(this.executor.execute(eq(LICENSE_CHECKER), any())).thenReturn(TestData.LICENSES);
+ when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null));
+ when(this.executor.execute(eq(LIST_DEPENDENCIES), any()))
+ .thenReturn(new ProcessResult(TestData.DEPENDENCIES, null));
+ when(this.executor.execute(eq(LICENSE_CHECKER), any())).thenReturn(new ProcessResult(TestData.LICENSES, null));
final PackageJson current = TestData.samplePackageJson();
assertThat(testee().getDependencies(current), Matchers.isA(ProjectDependencies.class));
}
@@ -68,8 +68,9 @@ void previousNotFound() throws FileNotFoundException {
@Test
void dependenciesFetchedOnlyOnceForWorkingDir() {
- when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn("");
- when(this.executor.execute(eq(LIST_DEPENDENCIES), any())).thenReturn(TestData.DEPENDENCIES);
+ when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null));
+ when(this.executor.execute(eq(LIST_DEPENDENCIES), any()))
+ .thenReturn(new ProcessResult(TestData.DEPENDENCIES, null));
final NpmServices testee = testee();
final Path workingDir = Path.of("testing-working-dir");
testee.listDependencies(workingDir);
@@ -79,8 +80,9 @@ void dependenciesFetchedOnlyOnceForWorkingDir() {
@Test
void dependenciesFetchedForEachWorkingDir() {
- when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn("");
- when(this.executor.execute(eq(LIST_DEPENDENCIES), any())).thenReturn(TestData.DEPENDENCIES);
+ when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null));
+ when(this.executor.execute(eq(LIST_DEPENDENCIES), any()))
+ .thenReturn(new ProcessResult(TestData.DEPENDENCIES, null));
final NpmServices testee = testee();
final Path workingDir1 = Path.of("testing-working-dir1");
final Path workingDir2 = Path.of("testing-working-dir2");
@@ -92,7 +94,7 @@ void dependenciesFetchedForEachWorkingDir() {
@Test
void fetchDependenciesSucceeds() {
- when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn("");
+ when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null));
assertDoesNotThrow(() -> testee().fetchDependencies(Path.of("testing-working-dir1")));
}
@@ -101,8 +103,10 @@ void fetchDependenciesFailsWithIllegalStateException() {
when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenThrow(IllegalStateException.class);
final NpmServices testee = testee();
final Path workingDir = Path.of("testing-working-dir1");
- final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> testee.fetchDependencies(workingDir));
- assertThat(exception.getMessage(), equalTo("E-PK-CORE-168: Installing dependencies in 'testing-working-dir1' via 'npm ci' failed. Try running 'npm ci' manually in directory 'testing-working-dir1'."));
+ final IllegalStateException exception = assertThrows(IllegalStateException.class,
+ () -> testee.fetchDependencies(workingDir));
+ assertThat(exception.getMessage(), equalTo(
+ "E-PK-CORE-168: Installing dependencies in 'testing-working-dir1' via 'npm ci' failed. Try running 'npm ci' manually in directory 'testing-working-dir1'."));
}
private PackageJson currentPackageJson(final Path relative) {
From 8e7d22b9ce2dcbf1b2ecd06129c41fe7f375d549 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 8 Feb 2024 08:54:47 +0100
Subject: [PATCH 68/78] Add assertion for maven command
---
.../sources/analyze/generic/MavenProcessBuilder.java | 6 +++++-
.../ProjectVersionIncrementorTest.java | 11 ++++++++---
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
index 0e002cbb..f630a03c 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
@@ -83,7 +83,11 @@ public MavenProcessBuilder timeout(final Duration timeout) {
* @return the built command
*/
public ShellCommand buildCommand() {
- return ShellCommand.builder().command(getMavenExecutable()).args(this.args).timeout(this.timeout).build();
+ return ShellCommand.builder().command(getMavenExecutable()) //
+ .args(this.args) //
+ .timeout(this.timeout) //
+ .workingDir(workingDir) //
+ .build();
}
private static String getMavenExecutable() {
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java
index 5a9432ec..caac26e4 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java
@@ -93,9 +93,14 @@ void incrementProjectVersionWithJarArtifactUpdatesReferences() {
when(pomFileIOMock.readPom(POM_PATH)).thenReturn(pomModel);
final String newVersion = testee(configWithJarArtifact(), CURRENT_PROJECT_VERSION).incrementProjectVersion();
assertAll(() -> assertThat(newVersion, equalTo("1.2.4")),
- () -> assertThat(pomModel.getVersion(), equalTo(newVersion)),
- () -> assertThat(getExecutedCommand().commandline(), contains(startsWith("mvn"),
- equalTo("--batch-mode"), equalTo("artifact-reference-checker:unify"))));
+ () -> assertThat(pomModel.getVersion(), equalTo(newVersion)), () -> assertMavenExecuted());
+ }
+
+ private void assertMavenExecuted(final String... mavenArguments) {
+ final ShellCommand command = getExecutedCommand();
+ assertThat(command.workingDir().get(), equalTo(PROJECT_DIR));
+ assertThat(command.commandline(),
+ contains(startsWith("mvn"), equalTo("--batch-mode"), equalTo("artifact-reference-checker:unify")));
}
private ShellCommand getExecutedCommand() {
From aa9f7f345309de3bfb1d3fd394608ec5916b0511 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 8 Feb 2024 11:24:42 +0100
Subject: [PATCH 69/78] Fix test for windows
---
.../dependencyupdate/ProjectVersionIncrementorTest.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java
index caac26e4..28d3ad5c 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementorTest.java
@@ -69,8 +69,9 @@ void incrementProjectVersionFailsForInconsistentVersionInPom() {
final IllegalStateException exception = assertThrows(IllegalStateException.class,
testee::incrementProjectVersion);
- assertThat(exception.getMessage(), startsWith(
- "E-PK-CORE-174: Inconsistent project version '1.2.2' found in pom 'ProjectDir/pom.xml', expected '1.2.3'."));
+ assertThat(exception.getMessage(),
+ startsWith("E-PK-CORE-174: Inconsistent project version '1.2.2' found in pom '" + POM_PATH
+ + "', expected '1.2.3'."));
}
@ParameterizedTest
From e5e4a4d98c15399eacf4e8c3cd22e6af8919c488 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 8 Feb 2024 14:15:09 +0100
Subject: [PATCH 70/78] Refactor command executor
---
...nProjectWithProjectKeeperPluginWriter.java | 10 ++--
.../JavaProjectCrawlerRunner.java | 11 ++--
.../sources/analyze/MavenSourceAnalyzer.java | 13 +----
.../analyze/generic/CommandExecutor.java | 19 +++++--
.../analyze/generic/MavenProcessBuilder.java | 32 +++++++++---
.../analyze/generic/ProcessResult.java | 38 ++++++++++++++
.../sources/analyze/generic/ShellCommand.java | 30 ++++++++++-
.../analyze/generic/SimpleProcess.java | 9 ++++
.../sources/analyze/golang/GoBinary.java | 2 +-
.../analyze/golang/GolangServices.java | 10 ++--
.../sources/analyze/npm/NpmServices.java | 2 +-
.../validators/changesfile/ChangesFile.java | 2 +-
.../validators/pom/PomFileIO.java | 52 +++++++++++++++++++
.../JavaProjectCrawlerRunnerIT.java | 9 ++--
.../sources/analyze/golang/GoBinaryTest.java | 4 +-
.../sources/analyze/npm/NpmServicesTest.java | 28 +++++-----
.../validators/pom/PomFileValidatorTest.java | 22 +++-----
17 files changed, 215 insertions(+), 78 deletions(-)
create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java
create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java
diff --git a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java
index 11953af5..0cb66aef 100644
--- a/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java
+++ b/project-keeper-maven-plugin/src/test/java/com/exasol/projectkeeper/plugin/MvnProjectWithProjectKeeperPluginWriter.java
@@ -1,13 +1,13 @@
package com.exasol.projectkeeper.plugin;
-import java.io.*;
import java.nio.file.Path;
import java.util.List;
import org.apache.maven.model.*;
-import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.codehaus.plexus.util.xml.Xpp3Dom;
+import com.exasol.projectkeeper.validators.pom.PomFileIO;
+
public class MvnProjectWithProjectKeeperPluginWriter {
public static final String PROJECT_ARTIFACT_ID = "my-test-project";
public static final String PROJECT_VERSION = "0.1.0";
@@ -26,11 +26,7 @@ public MvnProjectWithProjectKeeperPluginWriter(final String projectKeeperVersion
public void writeAsPomToProject(final Path projectDir) {
final Path path = projectDir.resolve("pom.xml");
- try (final FileWriter fileWriter = new FileWriter(path.toFile())) {
- new MavenXpp3Writer().write(fileWriter, this.model);
- } catch (final IOException exception) {
- throw new UncheckedIOException("Failed writing POM to file " + path, exception);
- }
+ new PomFileIO().writePom(model, path);
}
public MvnProjectWithProjectKeeperPluginWriter addDependency(final String groupId, final String artifactId,
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java
index 18dcf1ed..b419defa 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/JavaProjectCrawlerRunner.java
@@ -8,8 +8,7 @@
import com.exasol.projectkeeper.shared.mavenprojectcrawler.MavenProjectCrawlResult;
import com.exasol.projectkeeper.shared.mavenprojectcrawler.ResponseCoder;
-import com.exasol.projectkeeper.sources.analyze.generic.MavenProcessBuilder;
-import com.exasol.projectkeeper.sources.analyze.generic.SimpleProcess;
+import com.exasol.projectkeeper.sources.analyze.generic.*;
/**
* Runs the maven plugin goal on the current repository and returns the parsed result.
@@ -43,9 +42,8 @@ public MavenProjectCrawlResult crawlProject(final Path... pomFiles) {
private String runCrawlerPlugin(final Path... pomFiles) {
final MavenProcessBuilder builder = buildMavenCommand(pomFiles);
- final SimpleProcess process = builder.startSimpleProcess();
- process.waitUntilFinished(Duration.ofSeconds(90));
- return new ResponseCoder().decodeResponse(process.getOutputStreamContent());
+ final ProcessResult result = new CommandExecutor().execute(builder.buildCommand());
+ return new ResponseCoder().decodeResponse(result.getOutputStreamContent());
}
private MavenProcessBuilder buildMavenCommand(final Path... pomFiles) {
@@ -60,7 +58,8 @@ private MavenProcessBuilder buildMavenCommand(final Path... pomFiles) {
* comparing dependencies).
*/
"-Dmaven.defaultProjectBuilder.disableGlobalModelCache=true")
- .workingDir(null);
+ .workingDir(null) //
+ .timeout(Duration.ofSeconds(90));
if (this.mvnRepositoryOverride != null) {
builder.addArgument("-Dmaven.repo.local=" + this.mvnRepositoryOverride);
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java
index f02e8ff9..1f550b76 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/MavenSourceAnalyzer.java
@@ -3,7 +3,6 @@
import static com.exasol.projectkeeper.shared.config.SourceType.MAVEN;
import static java.util.Collections.emptyMap;
-import java.io.FileInputStream;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.List;
@@ -11,7 +10,6 @@
import java.util.stream.Collectors;
import org.apache.maven.model.Model;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import com.exasol.errorreporting.ExaError;
import com.exasol.projectkeeper.JavaProjectCrawlerRunner;
@@ -19,6 +17,7 @@
import com.exasol.projectkeeper.shared.mavenprojectcrawler.CrawledMavenProject;
import com.exasol.projectkeeper.sources.AnalyzedMavenSource;
import com.exasol.projectkeeper.sources.AnalyzedSource;
+import com.exasol.projectkeeper.validators.pom.PomFileIO;
/**
* This class analyzes Java Maven projects.
@@ -106,14 +105,6 @@ private CrawledMavenProject getCrawlResultForProject(final Source source,
}
private Model readMavenModel(final Source source) {
- try (final FileInputStream fileInputStream = new FileInputStream(source.getPath().toFile())) {
- return new MavenXpp3Reader().read(fileInputStream);
- } catch (final Exception exception) {
- // Catch Exception instead of org.codehaus.plexus.util.xml.pull.XmlPullParserException helps avoid adding
- // runtime dependency org.codehaus.plexus:plexus-utils
- throw new IllegalStateException(
- ExaError.messageBuilder("E-PK-CORE-94").message("Failed to analyze maven source.").toString(),
- exception);
- }
+ return new PomFileIO().readPom(source.getPath());
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java
index c6410a73..bd8f3aea 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/CommandExecutor.java
@@ -8,16 +8,27 @@
public class CommandExecutor {
/**
- * Executes the specified {@link ShellCommand}
+ * Executes the specified {@link ShellCommand}.
*
* @param sc command to execute
* @param workingDirectory directory to run the execution in
- * @return standard output of the command
+ * @return standard and error output of the command
* @throws IllegalStateException if execution fails.
*/
- public String execute(final ShellCommand sc, final Path workingDirectory) throws IllegalStateException {
+ public ProcessResult execute(final ShellCommand sc, final Path workingDirectory) throws IllegalStateException {
final SimpleProcess process = SimpleProcess.start(workingDirectory, sc.commandline());
process.waitUntilFinished(sc.timeout());
- return process.getOutputStreamContent();
+ return process.getResult();
+ }
+
+ /**
+ * Executes the specified {@link ShellCommand}.
+ *
+ * @param sc command to execute
+ * @return standard and error output of the command
+ * @throws IllegalStateException if execution fails.
+ */
+ public ProcessResult execute(final ShellCommand sc) throws IllegalStateException {
+ return execute(sc, sc.workingDir().orElse(null));
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
index b8252558..5dfd7877 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/MavenProcessBuilder.java
@@ -3,6 +3,7 @@
import static java.util.Arrays.asList;
import java.nio.file.Path;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@@ -12,8 +13,9 @@
* This class allows building and starting a {@code mvn} command.
*/
public class MavenProcessBuilder {
- private final List command = new ArrayList<>();
+ private final List args = new ArrayList<>();
private Path workingDir = null;
+ private Duration timeout = null;
private MavenProcessBuilder() {
// Use create() method
@@ -26,7 +28,6 @@ private MavenProcessBuilder() {
*/
public static MavenProcessBuilder create() {
final MavenProcessBuilder builder = new MavenProcessBuilder();
- builder.addArgument(getMavenExecutable());
builder.addArgument("--batch-mode");
return builder;
}
@@ -38,7 +39,7 @@ public static MavenProcessBuilder create() {
* @return {@code this} for fluent programming
*/
public MavenProcessBuilder addArguments(final String... arguments) {
- command.addAll(asList(arguments));
+ args.addAll(asList(arguments));
return this;
}
@@ -49,7 +50,7 @@ public MavenProcessBuilder addArguments(final String... arguments) {
* @return {@code this} for fluent programming
*/
public MavenProcessBuilder addArgument(final String argument) {
- command.add(argument);
+ args.add(argument);
return this;
}
@@ -65,12 +66,27 @@ public MavenProcessBuilder workingDir(final Path workingDir) {
}
/**
- * Build the command and run it.
+ * Set the timeout for running the process.
*
- * @return the running {@link SimpleProcess}
+ * @param timeout process timeout
+ * @return {@code this} for fluent programming
+ */
+ public MavenProcessBuilder timeout(final Duration timeout) {
+ this.timeout = timeout;
+ return this;
+ }
+
+ /**
+ * Build a {@link ShellCommand} that can be started with {@link CommandExecutor}.
+ *
+ * @return the built command
*/
- public SimpleProcess startSimpleProcess() {
- return SimpleProcess.start(workingDir, command);
+ public ShellCommand buildCommand() {
+ return ShellCommand.builder().command(getMavenExecutable()) //
+ .args(this.args) //
+ .timeout(this.timeout) //
+ .workingDir(workingDir) //
+ .build();
}
private static String getMavenExecutable() {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java
new file mode 100644
index 00000000..baf30819
--- /dev/null
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java
@@ -0,0 +1,38 @@
+package com.exasol.projectkeeper.sources.analyze.generic;
+
+/**
+ * Result of executing a process.
+ */
+public class ProcessResult {
+ private final String outputStreamContent;
+ private final String errorStreamContent;
+
+ /**
+ * Create a new process result.
+ *
+ * @param outputStreamContent output stream content
+ * @param errorStreamContent error stream content
+ */
+ public ProcessResult(final String outputStreamContent, final String errorStreamContent) {
+ this.outputStreamContent = outputStreamContent;
+ this.errorStreamContent = errorStreamContent;
+ }
+
+ /**
+ * Content of the output stream.
+ *
+ * @return output stream
+ */
+ public String getOutputStreamContent() {
+ return outputStreamContent;
+ }
+
+ /**
+ * Content of the error stream.
+ *
+ * @return error stream
+ */
+ public String getErrorStreamContent() {
+ return errorStreamContent;
+ }
+}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java
index 076d1488..c69471d8 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ShellCommand.java
@@ -1,5 +1,6 @@
package com.exasol.projectkeeper.sources.analyze.generic;
+import java.nio.file.Path;
import java.time.Duration;
import java.util.*;
import java.util.logging.Logger;
@@ -22,6 +23,7 @@ public static Builder builder() {
private Duration timeout;
private String mainCommand;
private String subCommand;
+ private Path workingDir = null;
private final List options = new ArrayList<>();
/**
@@ -52,6 +54,15 @@ public Duration timeout() {
return this.timeout;
}
+ /**
+ * Working directory for the process.
+ *
+ * @return working dir
+ */
+ public Optional workingDir() {
+ return Optional.ofNullable(this.workingDir);
+ }
+
/**
* Builder for a new instance of {@link ShellCommand}.
*/
@@ -67,6 +78,15 @@ public Builder timeout(final Duration timeout) {
return this;
}
+ /**
+ * @param workingDir optional working directory for the process
+ * @return this for fluent programming
+ */
+ public Builder workingDir(final Path workingDir) {
+ this.shellCommand.workingDir = workingDir;
+ return this;
+ }
+
/**
* @param command name of the command to execute. On Windows platform probably with a suffix like ".exe" or
* ".cmd", see {@link OsCheck#suffix}
@@ -94,7 +114,15 @@ public Builder command(final String main, final String sub) {
* @return this for fluent programming
*/
public Builder args(final String... value) {
- this.shellCommand.options.addAll(Arrays.asList(value));
+ return this.args(Arrays.asList(value));
+ }
+
+ /**
+ * @param value additional options and arguments to the command
+ * @return this for fluent programming
+ */
+ public Builder args(final List value) {
+ this.shellCommand.options.addAll(value);
return this;
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java
index cf1903a3..a07fe90c 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/SimpleProcess.java
@@ -129,6 +129,15 @@ public String getErrorStreamContent() {
}
}
+ /**
+ * Get the process result containing output and error stream content.
+ *
+ * @return result
+ */
+ public ProcessResult getResult() {
+ return new ProcessResult(getOutputStreamContent(), getErrorStreamContent());
+ }
+
private void waitForExecutionFinished(final Duration executionTimeout) {
try {
if (!this.process.waitFor(executionTimeout.toMillis(), TimeUnit.MILLISECONDS)) {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java
index 40f22564..b4c8caa7 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinary.java
@@ -63,7 +63,7 @@ public GoBinary install() {
.args("install", this.moduleName) //
.build();
try {
- this.executor.execute(shellCommand, null);
+ this.executor.execute(shellCommand);
} catch (final IllegalStateException exception) {
throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-161")
.message("Error installing go binary {{binary}}.", this.binaryName).toString(), exception);
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java
index 443814d3..aad86426 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/golang/GolangServices.java
@@ -78,9 +78,9 @@ private String retrieveLicenses(final Path absoluteSourcePath, final String modu
.timeout(EXECUTION_TIMEOUT) //
.command(goLicenses.command()) //
.args("csv", module) //
- .build();
+ .workingDir(absoluteSourcePath).build();
try {
- return this.executor.execute(shellCommand, absoluteSourcePath);
+ return this.executor.execute(shellCommand).getOutputStreamContent();
} catch (final RuntimeException exception) {
throw new IllegalStateException(
ExaError.messageBuilder("E-PK-CORE-142")
@@ -100,8 +100,9 @@ Path getModuleDir(final Path absoluteSourcePath, final String moduleName) {
.timeout(Duration.ofSeconds(3)) //
.command(GoBinary.GO.command()) //
.args("list", "-m", "-f", "{{.Dir}}", moduleName) //
+ .workingDir(absoluteSourcePath) //
.build();
- final String output = this.executor.execute(shellCommand, absoluteSourcePath).trim();
+ final String output = this.executor.execute(shellCommand).getOutputStreamContent().trim();
if (output.isEmpty()) {
throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-160")
.message("Did not get directory for module {{module name}}.", moduleName).ticketMitigation()
@@ -226,7 +227,8 @@ void installDependencies(final Path projectPath) {
.timeout(Duration.ofMinutes(2)) //
.command(GoBinary.GO.command()) //
.args("get", "-t", "./...") //
+ .workingDir(projectPath) //
.build();
- this.executor.execute(sc, projectPath);
+ this.executor.execute(sc);
}
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java
index 1128a165..ac1d9755 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServices.java
@@ -72,7 +72,7 @@ JsonObject getLicenses(final Path folder) {
private JsonObject getJsonOutput(final ShellCommand cmd, final Path workingDir) {
fetchDependencies(workingDir);
- final String stdout = this.executor.execute(cmd, workingDir);
+ final String stdout = this.executor.execute(cmd, workingDir).getOutputStreamContent();
return JsonIo.read(new StringReader(stdout));
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
index c2e02c54..05a08ca0 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/changesfile/ChangesFile.java
@@ -109,7 +109,7 @@ public String getCodeName() {
*/
public Optional getParsedReleaseDate() {
try {
- return Optional.of(LocalDate.parse(this.getReleaseDate()));
+ return Optional.ofNullable(this.getReleaseDate()).map(LocalDate::parse);
} catch (final DateTimeParseException exception) {
return Optional.empty();
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java
new file mode 100644
index 00000000..9560b2fb
--- /dev/null
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java
@@ -0,0 +1,52 @@
+package com.exasol.projectkeeper.validators.pom;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+import com.exasol.errorreporting.ExaError;
+
+/**
+ * This class reads and writes POM files.
+ */
+public class PomFileIO {
+
+ private static final MavenXpp3Writer WRITER = new MavenXpp3Writer();
+ private static final MavenXpp3Reader READER = new MavenXpp3Reader();
+
+ /**
+ * Read the given file and parse it as a POM file.
+ *
+ * @param path path to read
+ * @return parsed POM model
+ */
+ public Model readPom(final Path path) {
+ try {
+ return READER.read(Files.newBufferedReader(path));
+ } catch (IOException | XmlPullParserException exception) {
+ throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-172")
+ .message("Failed to read pom {{pom file path}}", path).toString(), exception);
+ }
+ }
+
+ /**
+ * Write a POM model to a file
+ *
+ * @param model the POM model to write
+ * @param path the path to write
+ */
+ public void writePom(final Model model, final Path path) {
+ try {
+ WRITER.write(Files.newOutputStream(path), model);
+ } catch (final IOException exception) {
+ throw new UncheckedIOException(ExaError.messageBuilder("E-PK-CORE-173")
+ .message("Failed to write pom {{pom file path}}", path).toString(), exception);
+ }
+ }
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
index ea11a2c7..0432ec36 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/JavaProjectCrawlerRunnerIT.java
@@ -6,12 +6,10 @@
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertThrows;
-import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
-import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.hamcrest.Matchers;
@@ -26,6 +24,7 @@
import com.exasol.projectkeeper.shared.mavenprojectcrawler.CrawledMavenProject;
import com.exasol.projectkeeper.shared.mavenprojectcrawler.MavenProjectCrawlResult;
import com.exasol.projectkeeper.test.TestMavenModel;
+import com.exasol.projectkeeper.validators.pom.PomFileIO;
@Tag("integration")
class JavaProjectCrawlerRunnerIT {
@@ -83,11 +82,9 @@ void testGetDependencyChangesFailsForMissingPom() throws GitAPIException, IOExce
allOf(containsString("[FATAL] Non-readable POM"), containsString(missingPomFile.toString())));
}
- private void writePomFile(final Path pomFile) throws IOException {
+ private void writePomFile(final Path pomFile) {
final TestMavenModel model = new TestMavenModel();
model.addDependency(DEPENDENCY_ID, DEPENDENCY_GROUP, "", DEPENDENCY_VERSION);
- try (final FileWriter fileWriter = new FileWriter(pomFile.toFile())) {
- new MavenXpp3Writer().write(fileWriter, model);
- }
+ new PomFileIO().writePom(model, pomFile);
}
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java
index 94cb90a8..5a47f174 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/golang/GoBinaryTest.java
@@ -46,7 +46,7 @@ void goItself() {
@Test
void installFailure() {
- when(this.executor.execute(any(), any())).thenThrow(new IllegalStateException("bla bla"));
+ when(this.executor.execute(any())).thenThrow(new IllegalStateException("bla bla"));
final GoBinary testee = testee();
final Exception e = assertThrows(IllegalStateException.class, () -> testee.install());
assertThat(e.getMessage(), Matchers.startsWith("E-PK-CORE-161: Error installing go binary"));
@@ -56,7 +56,7 @@ void installFailure() {
@Test
void installSuccess() {
testee().install();
- verify(this.executor).execute(any(), any());
+ verify(this.executor).execute(any());
}
@Test
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java
index d892d412..b6270772 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/npm/NpmServicesTest.java
@@ -22,8 +22,7 @@
import com.exasol.projectkeeper.shared.dependencies.ProjectDependencies;
import com.exasol.projectkeeper.shared.repository.GitRepository;
import com.exasol.projectkeeper.shared.repository.TaggedCommit;
-import com.exasol.projectkeeper.sources.analyze.generic.CommandExecutor;
-import com.exasol.projectkeeper.sources.analyze.generic.GitService;
+import com.exasol.projectkeeper.sources.analyze.generic.*;
@ExtendWith(MockitoExtension.class)
class NpmServicesTest {
@@ -40,9 +39,10 @@ class NpmServicesTest {
@Test
void getDependencies() {
- when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn("");
- when(this.executor.execute(eq(LIST_DEPENDENCIES), any())).thenReturn(TestData.DEPENDENCIES);
- when(this.executor.execute(eq(LICENSE_CHECKER), any())).thenReturn(TestData.LICENSES);
+ when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null));
+ when(this.executor.execute(eq(LIST_DEPENDENCIES), any()))
+ .thenReturn(new ProcessResult(TestData.DEPENDENCIES, null));
+ when(this.executor.execute(eq(LICENSE_CHECKER), any())).thenReturn(new ProcessResult(TestData.LICENSES, null));
final PackageJson current = TestData.samplePackageJson();
assertThat(testee().getDependencies(current), Matchers.isA(ProjectDependencies.class));
}
@@ -68,8 +68,9 @@ void previousNotFound() throws FileNotFoundException {
@Test
void dependenciesFetchedOnlyOnceForWorkingDir() {
- when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn("");
- when(this.executor.execute(eq(LIST_DEPENDENCIES), any())).thenReturn(TestData.DEPENDENCIES);
+ when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null));
+ when(this.executor.execute(eq(LIST_DEPENDENCIES), any()))
+ .thenReturn(new ProcessResult(TestData.DEPENDENCIES, null));
final NpmServices testee = testee();
final Path workingDir = Path.of("testing-working-dir");
testee.listDependencies(workingDir);
@@ -79,8 +80,9 @@ void dependenciesFetchedOnlyOnceForWorkingDir() {
@Test
void dependenciesFetchedForEachWorkingDir() {
- when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn("");
- when(this.executor.execute(eq(LIST_DEPENDENCIES), any())).thenReturn(TestData.DEPENDENCIES);
+ when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null));
+ when(this.executor.execute(eq(LIST_DEPENDENCIES), any()))
+ .thenReturn(new ProcessResult(TestData.DEPENDENCIES, null));
final NpmServices testee = testee();
final Path workingDir1 = Path.of("testing-working-dir1");
final Path workingDir2 = Path.of("testing-working-dir2");
@@ -92,7 +94,7 @@ void dependenciesFetchedForEachWorkingDir() {
@Test
void fetchDependenciesSucceeds() {
- when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn("");
+ when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenReturn(new ProcessResult("", null));
assertDoesNotThrow(() -> testee().fetchDependencies(Path.of("testing-working-dir1")));
}
@@ -101,8 +103,10 @@ void fetchDependenciesFailsWithIllegalStateException() {
when(this.executor.execute(eq(FETCH_DEPENDENCIES), any())).thenThrow(IllegalStateException.class);
final NpmServices testee = testee();
final Path workingDir = Path.of("testing-working-dir1");
- final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> testee.fetchDependencies(workingDir));
- assertThat(exception.getMessage(), equalTo("E-PK-CORE-168: Installing dependencies in 'testing-working-dir1' via 'npm ci' failed. Try running 'npm ci' manually in directory 'testing-working-dir1'."));
+ final IllegalStateException exception = assertThrows(IllegalStateException.class,
+ () -> testee.fetchDependencies(workingDir));
+ assertThat(exception.getMessage(), equalTo(
+ "E-PK-CORE-168: Installing dependencies in 'testing-working-dir1' via 'npm ci' failed. Try running 'npm ci' manually in directory 'testing-working-dir1'."));
}
private PackageJson currentPackageJson(final Path relative) {
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java
index 7bffedf2..e3b32bf5 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java
@@ -8,7 +8,6 @@
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.mockito.Mockito.mock;
-import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -16,7 +15,6 @@
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
@@ -115,33 +113,29 @@ private void runFix(final ParentPomRef parentPomRef) {
}
@Test
- void testMissingVersion() throws IOException {
+ void testMissingVersion() {
getTestModel().withVersion(null).writeAsPomToProject(this.tempDir);
assertThat(runValidator(null),
hasFindingWithMessageMatchingRegex("(?s)E-PK-CORE-111: Failed to detect project version.*"));
}
@Test
- void testMissingVersionButParentPomRef() throws IOException, XmlPullParserException {
+ void testMissingVersionButParentPomRef() {
getTestModel().withVersion(null).withParentVersion("2.3.4").writeAsPomToProject(this.tempDir);
runFix(new ParentPomRef("com.example", "my-parent", "1.2.3", null));
- try (final FileReader reader = new FileReader(this.tempDir.resolve("pk_generated_parent.pom").toFile())) {
- final Model pom = new MavenXpp3Reader().read(reader);
- assertThat(pom.getVersion(), equalTo("1.2.3"));
- }
+ final Model pom = new PomFileIO().readPom(this.tempDir.resolve("pk_generated_parent.pom"));
+ assertThat(pom.getVersion(), equalTo("1.2.3"));
}
@Test
- void testMissingVersionButFromParent() throws IOException, XmlPullParserException {
+ void testMissingVersionButFromParent() {
getTestModel().withVersion(null).withParentVersion("2.3.4").writeAsPomToProject(this.tempDir);
assertThat(runValidator(null),
not(hasFindingWithMessageMatchingRegex("(?s)E-PK-CORE-111: Failed to detect project version.*")));
}
- private Model readModel(final Path projectDir) throws XmlPullParserException, IOException {
- try (final FileReader fileReader = new FileReader(projectDir.toFile())) {
- return new MavenXpp3Reader().read(fileReader);
- }
+ private Model readModel(final Path projectDir) {
+ return new PomFileIO().readPom(projectDir);
}
@Test
@@ -279,4 +273,4 @@ void testValidAfterFix() throws IOException {
assertThat(result, empty());
}
-}
\ No newline at end of file
+}
From d348f15de879691b4cc57523d8f99d260628cee7 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 8 Feb 2024 14:37:18 +0100
Subject: [PATCH 71/78] Add unit tests
---
.../analyze/generic/ProcessResult.java | 31 +++++++++-
.../validators/pom/PomFileIO.java | 2 +-
.../validators/pom/io/PomFileReader.java | 5 +-
.../validators/pom/io/PomFileWriter.java | 5 +-
.../analyze/generic/ProcessResultTest.java | 19 ++++++
.../validators/pom/PomFileIOTest.java | 60 +++++++++++++++++++
6 files changed, 118 insertions(+), 4 deletions(-)
create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResultTest.java
create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileIOTest.java
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java
index baf30819..598ea333 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResult.java
@@ -1,9 +1,11 @@
package com.exasol.projectkeeper.sources.analyze.generic;
+import java.util.Objects;
+
/**
* Result of executing a process.
*/
-public class ProcessResult {
+public final class ProcessResult {
private final String outputStreamContent;
private final String errorStreamContent;
@@ -35,4 +37,31 @@ public String getOutputStreamContent() {
public String getErrorStreamContent() {
return errorStreamContent;
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(outputStreamContent, errorStreamContent);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ProcessResult other = (ProcessResult) obj;
+ return Objects.equals(outputStreamContent, other.outputStreamContent)
+ && Objects.equals(errorStreamContent, other.errorStreamContent);
+ }
+
+ @Override
+ public String toString() {
+ return "ProcessResult [outputStreamContent=" + outputStreamContent + ", errorStreamContent="
+ + errorStreamContent + "]";
+ }
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java
index 9560b2fb..97a400be 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java
@@ -13,7 +13,7 @@
import com.exasol.errorreporting.ExaError;
/**
- * This class reads and writes POM files.
+ * This class reads and writes POM files using the Maven POM {@link Model} class.
*/
public class PomFileIO {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java
index 970ae9b2..dda099bd 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java
@@ -11,9 +11,12 @@
import org.xml.sax.SAXException;
import com.exasol.errorreporting.ExaError;
+import com.exasol.projectkeeper.validators.pom.PomFileIO;
/**
- * This class implements reading a POM file.
+ * This class implements reading a POM file as an XML document.
+ *
+ * Use {@link PomFileIO} if you need the Maven POM model.
*/
public class PomFileReader {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java
index 60cb3d4b..dfe56b12 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java
@@ -12,9 +12,12 @@
import org.w3c.dom.Document;
import com.exasol.errorreporting.ExaError;
+import com.exasol.projectkeeper.validators.pom.PomFileIO;
/**
- * This class implements write access to a pom file.
+ * This class implements write access to a POM file as an XML document.
+ *
+ * Use {@link PomFileIO} if you need the Maven POM model.
*/
public class PomFileWriter {
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResultTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResultTest.java
new file mode 100644
index 00000000..460a4932
--- /dev/null
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/sources/analyze/generic/ProcessResultTest.java
@@ -0,0 +1,19 @@
+package com.exasol.projectkeeper.sources.analyze.generic;
+
+import org.junit.jupiter.api.Test;
+
+import com.jparams.verifier.tostring.ToStringVerifier;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class ProcessResultTest {
+ @Test
+ void testEqualsContract() {
+ EqualsVerifier.forClass(ProcessResult.class).verify();
+ }
+
+ @Test
+ void testToString() {
+ ToStringVerifier.forClass(ProcessResult.class).verify();
+ }
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileIOTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileIOTest.java
new file mode 100644
index 00000000..7a219b6e
--- /dev/null
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileIOTest.java
@@ -0,0 +1,60 @@
+package com.exasol.projectkeeper.validators.pom;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.maven.model.Model;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+class PomFileIOTest {
+
+ @TempDir
+ Path tempDir;
+
+ @Test
+ void write() throws IOException {
+ final Path file = tempDir.resolve("pom.xml");
+ final Model model = new Model();
+ model.setArtifactId("dummy-artifact");
+ testee().writePom(model, file);
+ assertThat(Files.readString(file), allOf(startsWith(""),
+ containsString("dummy-artifact"), endsWith("\n")));
+ }
+
+ @Test
+ void writeFails() throws IOException {
+ final Path file = tempDir.resolve("non-existing-dir").resolve("pom.xml");
+ final Model model = new Model();
+ final PomFileIO testee = testee();
+ final UncheckedIOException exception = assertThrows(UncheckedIOException.class,
+ () -> testee.writePom(model, file));
+ assertThat(exception.getMessage(), startsWith("E-PK-CORE-173: Failed to write pom"));
+ }
+
+ @Test
+ void read() throws IOException {
+ final Path file = Path.of("pom.xml");
+ final Model pom = testee().readPom(file);
+ assertThat(pom.getArtifactId(), equalTo("project-keeper-core"));
+ }
+
+ @Test
+ void readFails() throws IOException {
+ final Path file = tempDir.resolve("pom.xml");
+ final PomFileIO testee = testee();
+ final IllegalStateException exception = assertThrows(IllegalStateException.class, () -> testee.readPom(file));
+ assertThat(exception.getMessage(), startsWith("E-PK-CORE-172: Failed to read pom"));
+ }
+
+ private PomFileIO testee() {
+ return new PomFileIO();
+ }
+
+}
From 029b56b51b7b8d8860aea7dca350665724698193 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 8 Feb 2024 14:41:14 +0100
Subject: [PATCH 72/78] Add comments
---
.../com/exasol/projectkeeper/validators/pom/PomFileIO.java | 3 +++
.../exasol/projectkeeper/validators/pom/io/PomFileReader.java | 3 +--
.../exasol/projectkeeper/validators/pom/io/PomFileWriter.java | 3 +--
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java
index 97a400be..fb8cbdc6 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/PomFileIO.java
@@ -14,6 +14,9 @@
/**
* This class reads and writes POM files using the Maven POM {@link Model} class.
+ *
+ * Use {@link com.exasol.projectkeeper.validators.pom.io.PomFileReader} or
+ * {@link com.exasol.projectkeeper.validators.pom.io.PomFileWriter} if you want to read/write POM files as XML.
*/
public class PomFileIO {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java
index dda099bd..5ff34b46 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileReader.java
@@ -11,12 +11,11 @@
import org.xml.sax.SAXException;
import com.exasol.errorreporting.ExaError;
-import com.exasol.projectkeeper.validators.pom.PomFileIO;
/**
* This class implements reading a POM file as an XML document.
*
- * Use {@link PomFileIO} if you need the Maven POM model.
+ * Use {@link com.exasol.projectkeeper.validators.pom.PomFileIO} if you need the Maven POM model.
*/
public class PomFileReader {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java
index dfe56b12..9073739c 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/pom/io/PomFileWriter.java
@@ -12,12 +12,11 @@
import org.w3c.dom.Document;
import com.exasol.errorreporting.ExaError;
-import com.exasol.projectkeeper.validators.pom.PomFileIO;
/**
* This class implements write access to a POM file as an XML document.
*
- * Use {@link PomFileIO} if you need the Maven POM model.
+ * Use {@link com.exasol.projectkeeper.validators.pom.PomFileIO} if you need the Maven POM model.
*/
public class PomFileWriter {
From 82080464fa20dd96078433dc9ae8bc607ddacf21 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Thu, 8 Feb 2024 14:43:32 +0100
Subject: [PATCH 73/78] Code cleanup
---
.../projectkeeper/validators/pom/PomFileValidatorTest.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java
index e3b32bf5..15de0da9 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/pom/PomFileValidatorTest.java
@@ -123,7 +123,7 @@ void testMissingVersion() {
void testMissingVersionButParentPomRef() {
getTestModel().withVersion(null).withParentVersion("2.3.4").writeAsPomToProject(this.tempDir);
runFix(new ParentPomRef("com.example", "my-parent", "1.2.3", null));
- final Model pom = new PomFileIO().readPom(this.tempDir.resolve("pk_generated_parent.pom"));
+ final Model pom = readModel(this.tempDir.resolve("pk_generated_parent.pom"));
assertThat(pom.getVersion(), equalTo("1.2.3"));
}
@@ -134,8 +134,8 @@ void testMissingVersionButFromParent() {
not(hasFindingWithMessageMatchingRegex("(?s)E-PK-CORE-111: Failed to detect project version.*")));
}
- private Model readModel(final Path projectDir) {
- return new PomFileIO().readPom(projectDir);
+ private Model readModel(final Path file) {
+ return new PomFileIO().readPom(file);
}
@Test
From 83701de5dcfebd1571bf8e19b259c559d93ceaf0 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Fri, 9 Feb 2024 08:22:42 +0100
Subject: [PATCH 74/78] Add unit tests
---
.../dependencyupdate/ChangesFileUpdater.java | 31 +++++-
.../dependencyupdate/DependencyUpdater.java | 26 ++---
.../ProjectVersionIncrementor.java | 9 ++
.../VulnerabilityInfoProvider.java | 9 ++
.../DependencyUpdaterTest.java | 102 +++++++++++++++---
5 files changed, 144 insertions(+), 33 deletions(-)
create mode 100644 project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/VulnerabilityInfoProvider.java
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java
index 63637e06..b7ab0979 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdater.java
@@ -1,12 +1,41 @@
package com.exasol.projectkeeper.dependencyupdate;
+import java.nio.file.Path;
+
import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
import com.exasol.projectkeeper.validators.changesfile.ChangesFile.Builder;
+import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO;
+/**
+ * This class updates the the changesfile (e.g. {@code doc/changes/changes_1.2.0.md} for a given version, adding
+ * information about fixed vulnerabilities in dependencies.
+ */
class ChangesFileUpdater {
- ChangesFile update(final ChangesFile changesFile) {
+ private final ChangesFileIO changesFileIO;
+ private final Path projectDir;
+ private final VulnerabilityInfoProvider vulnerabilityInfoProvider;
+
+ ChangesFileUpdater(final VulnerabilityInfoProvider vulnerabilityInfoProvider, final ChangesFileIO changesFileIO,
+ final Path projectDir) {
+ this.vulnerabilityInfoProvider = vulnerabilityInfoProvider;
+ this.changesFileIO = changesFileIO;
+ this.projectDir = projectDir;
+ }
+
+ void updateChanges(final String version) {
+ final Path changesFilePath = getChangesFilePath(version);
+ final ChangesFile changesFile = changesFileIO.read(changesFilePath);
+ final ChangesFile updatedChanges = update(changesFile);
+ changesFileIO.write(updatedChanges, changesFilePath);
+ }
+
+ private ChangesFile update(final ChangesFile changesFile) {
final Builder builder = changesFile.toBuilder();
// Changes file will be updated in the next PR
return builder.build();
}
+
+ private Path getChangesFilePath(final String version) {
+ return projectDir.resolve(ChangesFile.getPathForVersion(version));
+ }
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
index 224d0cb6..c4ce4335 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdater.java
@@ -8,7 +8,6 @@
import com.exasol.projectkeeper.ProjectKeeper;
import com.exasol.projectkeeper.shared.config.ProjectKeeperConfig;
import com.exasol.projectkeeper.sources.analyze.generic.*;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFile;
import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO;
/**
@@ -21,21 +20,18 @@ public class DependencyUpdater {
private final Logger logger;
private final Path projectDir;
private final ProjectVersionIncrementor projectVersionIncrementor;
- private final ChangesFileIO changesFileIO;
private final String currentProjectVersion;
private final ChangesFileUpdater changesFileUpdater;
private final CommandExecutor commandExecutor;
DependencyUpdater(final ProjectKeeper projectKeeper, final Logger logger, final Path projectDir,
final String currentProjectVersion, final ProjectVersionIncrementor projectVersionIncrementor,
- final ChangesFileIO changesFileIO, final ChangesFileUpdater changesFileUpdater,
- final CommandExecutor commandExecutor) {
+ final ChangesFileUpdater changesFileUpdater, final CommandExecutor commandExecutor) {
this.projectKeeper = projectKeeper;
this.logger = logger;
this.projectDir = projectDir;
this.currentProjectVersion = currentProjectVersion;
this.projectVersionIncrementor = projectVersionIncrementor;
- this.changesFileIO = changesFileIO;
this.changesFileUpdater = changesFileUpdater;
this.commandExecutor = commandExecutor;
}
@@ -53,8 +49,9 @@ public class DependencyUpdater {
public static DependencyUpdater create(final ProjectKeeper projectKeeper, final ProjectKeeperConfig config,
final Logger logger, final Path projectDir, final String currentProjectVersion) {
return new DependencyUpdater(projectKeeper, logger, projectDir, currentProjectVersion,
- new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion), new ChangesFileIO(),
- new ChangesFileUpdater(), new CommandExecutor());
+ new ProjectVersionIncrementor(config, logger, projectDir, currentProjectVersion),
+ new ChangesFileUpdater(new VulnerabilityInfoProvider(), new ChangesFileIO(), projectDir),
+ new CommandExecutor());
}
/**
@@ -72,7 +69,7 @@ public boolean updateDependencies() {
final String version = incrementProjectVersion();
updateDependencyVersions();
runProjectKeeperFix();
- updateChangelog(version);
+ changesFileUpdater.updateChanges(version);
return true;
}
@@ -98,22 +95,11 @@ private void runMaven(final String mavenGoal) {
}
private void runProjectKeeperFix() {
- logger.info("Running project-keeper fix");
+ logger.info("Running project-keeper fix...");
if (!projectKeeper.fix()) {
throw new IllegalStateException(ExaError.messageBuilder("E-PK-CORE-177")
.message("Running project-keeper fix failed, see errors above.")
.mitigation("Fix findings and try again.").toString());
}
}
-
- private void updateChangelog(final String version) {
- final Path changesFilePath = getChangesFilePath(version);
- final ChangesFile changesFile = changesFileIO.read(changesFilePath);
- final ChangesFile updatedChanges = changesFileUpdater.update(changesFile);
- changesFileIO.write(updatedChanges, changesFilePath);
- }
-
- private Path getChangesFilePath(final String version) {
- return projectDir.resolve(ChangesFile.getPathForVersion(version));
- }
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
index 3fe8ac8b..86ddf113 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/ProjectVersionIncrementor.java
@@ -18,6 +18,9 @@
import com.exasol.projectkeeper.validators.pom.PomFileIO;
import com.vdurmont.semver4j.Semver;
+/**
+ * This class can increment the project's version.
+ */
class ProjectVersionIncrementor {
private static final ZoneId UTC_ZONE = ZoneId.of("UTC");
private final ProjectKeeperConfig config;
@@ -75,6 +78,12 @@ private LocalDate today() {
return LocalDate.ofInstant(clock.instant(), UTC_ZONE);
}
+ /**
+ * Increment the project's patch version. If the project produces a JAR (i.e. uses the {@code JAR_ARTIFACT} module),
+ * it runs its {@code artifact-reference-checker:unify} goal to update references to the JAR file.
+ *
+ * @return the new, incremented version
+ */
String incrementProjectVersion() {
final Path path = getPomPath();
final Model pom = pomFileIO.readPom(path);
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/VulnerabilityInfoProvider.java b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/VulnerabilityInfoProvider.java
new file mode 100644
index 00000000..345062a1
--- /dev/null
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/dependencyupdate/VulnerabilityInfoProvider.java
@@ -0,0 +1,9 @@
+package com.exasol.projectkeeper.dependencyupdate;
+
+/**
+ * This class provides access to information about vulnerabilities in dependencies that are potentially fixed by
+ * updating dependency versions.
+ */
+class VulnerabilityInfoProvider {
+ // Will be implemented in next PR
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java
index 27090fdd..73f25455 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/DependencyUpdaterTest.java
@@ -1,49 +1,127 @@
package com.exasol.projectkeeper.dependencyupdate;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.*;
import java.nio.file.Path;
+import java.util.List;
+import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
-import com.exasol.projectkeeper.Logger;
-import com.exasol.projectkeeper.ProjectKeeper;
+import com.exasol.projectkeeper.*;
import com.exasol.projectkeeper.sources.analyze.generic.CommandExecutor;
-import com.exasol.projectkeeper.validators.changesfile.ChangesFileIO;
+import com.exasol.projectkeeper.sources.analyze.generic.ShellCommand;
@ExtendWith(MockitoExtension.class)
class DependencyUpdaterTest {
private static final Path PROJECT_DIR = Path.of("ProjectDir");
private static final String CURRENT_PROJECT_VERSION = "1.2.3";
+ private static final String NEXT_PROJECT_VERSION = "1.2.4";
@Mock
private ProjectKeeper projectKeeperMock;
@Mock
- private Logger loggerMock;
- @Mock
private ProjectVersionIncrementor projectVersionIncrementorMock;
@Mock
- private ChangesFileIO changesFileIOMock;
- @Mock
private ChangesFileUpdater changesFileUpdaterMock;
@Mock
private CommandExecutor commandExecutorMock;
@Test
- void updateDependencies() {
- // assertUpdate();
+ void updateDependenciesIncrementsVersionIfRequired() {
+ when(projectKeeperMock.fix()).thenReturn(true);
+ when(projectVersionIncrementorMock.isCurrentVersionReleased()).thenReturn(true);
+ when(projectVersionIncrementorMock.incrementProjectVersion()).thenReturn(NEXT_PROJECT_VERSION);
+ assertUpdate();
+ verify(projectVersionIncrementorMock).incrementProjectVersion();
+ }
+
+ @Test
+ void updateDependenciesDoesNotIncrementsVersionIfNotRequired() {
+ when(projectKeeperMock.fix()).thenReturn(true);
+ when(projectVersionIncrementorMock.isCurrentVersionReleased()).thenReturn(false);
+ assertUpdate();
+ verify(projectVersionIncrementorMock, never()).incrementProjectVersion();
+ }
+
+ @Test
+ void updateDependenciesPKFixFails() {
+ when(projectKeeperMock.fix()).thenReturn(false);
+ final DependencyUpdater testee = testee();
+ final IllegalStateException exception = assertThrows(IllegalStateException.class, testee::updateDependencies);
+ assertThat(exception.getMessage(), equalTo(
+ "E-PK-CORE-177: Running project-keeper fix failed, see errors above. Fix findings and try again."));
+ }
+
+ @Test
+ void updateDependenciesPKFixSucceeds() {
+ when(projectKeeperMock.fix()).thenReturn(true);
+ assertUpdate();
+ verify(projectKeeperMock).fix();
+ }
+
+ @Test
+ void updateDependenciesRunsVersionsPlugin() {
+ when(projectKeeperMock.fix()).thenReturn(true);
+ assertUpdate();
+ final List commands = verifyCommandExecuted();
+ final ShellCommand useLatestVersion = commands.get(0);
+ final ShellCommand updateProperties = commands.get(1);
+ assertThat(useLatestVersion.workingDir().get(), equalTo(PROJECT_DIR));
+ assertThat(updateProperties.workingDir().get(), equalTo(PROJECT_DIR));
+ final String mavenExecutable = "mvn" + OsCheck.suffix(".cmd");
+ assertThat(useLatestVersion.commandline(),
+ Matchers.contains(mavenExecutable, "--batch-mode", "versions:use-latest-releases"));
+ assertThat(updateProperties.commandline(),
+ Matchers.contains(mavenExecutable, "--batch-mode", "versions:update-properties"));
+ }
+
+ @Test
+ void updateDependenciesUpdatesChangesFile() {
+ when(projectKeeperMock.fix()).thenReturn(true);
+ assertUpdate();
+ verify(changesFileUpdaterMock).updateChanges(CURRENT_PROJECT_VERSION);
+ }
+
+ private List verifyCommandExecuted() {
+ final ArgumentCaptor arg = ArgumentCaptor.forClass(ShellCommand.class);
+ verify(commandExecutorMock, times(2)).execute(arg.capture());
+ assertThat(arg.getAllValues(), hasSize(2));
+ return arg.getAllValues();
}
private DependencyUpdater testee() {
- return new DependencyUpdater(projectKeeperMock, loggerMock, PROJECT_DIR, CURRENT_PROJECT_VERSION,
- projectVersionIncrementorMock, changesFileIOMock, changesFileUpdaterMock, commandExecutorMock);
+ return new DependencyUpdater(projectKeeperMock, new PrintLogger(), PROJECT_DIR, CURRENT_PROJECT_VERSION,
+ projectVersionIncrementorMock, changesFileUpdaterMock, commandExecutorMock);
}
private void assertUpdate() {
assertThat(testee().updateDependencies(), is(true));
}
+
+ static class PrintLogger implements Logger {
+
+ @Override
+ public void info(final String message) {
+ System.out.println(message);
+ }
+
+ @Override
+ public void warn(final String message) {
+ System.out.println(message);
+ }
+
+ @Override
+ public void error(final String message) {
+ System.out.println(message);
+ }
+
+ }
}
From a25e3558dff6322bb8b9a230e9b7d52aa67de529 Mon Sep 17 00:00:00 2001
From: Christoph Pirkl
Date: Fri, 9 Feb 2024 12:23:14 +0100
Subject: [PATCH 75/78] Improve test coverage
---
parent-pom/pom.xml | 6 ++
project-keeper/pom.xml | 5 ++
.../exasol/projectkeeper/ProjectKeeper.java | 2 +-
.../validators/changesfile/ChangesFile.java | 13 +++--
.../projectkeeper/ProjectKeeperTest.java | 35 ++++++++++++
.../ChangesFileUpdaterTest.java | 55 +++++++++++++++++++
6 files changed, 111 insertions(+), 5 deletions(-)
create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/ProjectKeeperTest.java
create mode 100644 project-keeper/src/test/java/com/exasol/projectkeeper/dependencyupdate/ChangesFileUpdaterTest.java
diff --git a/parent-pom/pom.xml b/parent-pom/pom.xml
index a0ee2850..c7340981 100644
--- a/parent-pom/pom.xml
+++ b/parent-pom/pom.xml
@@ -202,6 +202,12 @@
1.2.0test