diff --git a/.github/workflows/default-tests.yml b/.github/workflows/default-tests.yml
index 13e9677b..2495ef47 100644
--- a/.github/workflows/default-tests.yml
+++ b/.github/workflows/default-tests.yml
@@ -31,7 +31,7 @@ jobs:
needs: checkstyle
strategy:
matrix:
- java_version: ['11', '12', '13', '14', '15', '16', '17', '18', '19', '20']
+ java_version: ['11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21']
steps:
- uses: actions/checkout@v4
@@ -59,7 +59,7 @@ jobs:
strategy:
matrix:
java_version: ['11']
- maven_version: ['3.2.5', '3.3.9', '3.5.4', '3.6.3', '3.8.8', '3.9.1', '3.9.2', '4.0.0-alpha-7']
+ maven_version: ['3.2.5', '3.3.9', '3.5.4', '3.6.3', '3.8.8', '3.9.6', '4.0.0-alpha-12']
steps:
- uses: actions/checkout@v4
diff --git a/pom.xml b/pom.xml
index a5b2e98f..c757aca3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -397,7 +397,7 @@
The current dateFormat is set to match maven's default {@code yyyy-MM-dd'T'HH:mm:ssZ}. - * Please note that in previous versions (2.2.0 - 2.2.2) the default dateFormat was set to: {@code - * dd.MM.yyyy '@' HH:mm:ss z}. However the {@code RFC 822 time zone} seems to give a more reliable - * option in parsing the date and it's being used in maven as default. + *
The current dateFormat will be formatted as ISO 8601 + * {@code yyyy-MM-dd'T'HH:mm:ssXXX} and therefore can be used as input to maven's + * + * reproducible build feature. + * + * Please note that in previous versions + * (2.2.2 - 7.0.1) the default format was set to {@code yyyy-MM-dd'T'HH:mm:ssZ} + * which produces a {@code RFC 822 time zone}. While such format gives reliable + * options in parsing the date, it does not comply with the requirements of + * the reproducible build feature. + * (2.2.0 - 2.2.2) the default dateFormat was set to: {@code + * dd.MM.yyyy '@' HH:mm:ss z}. * *
Example: * *
{@code - ** * @since 2.2.0 */ - @Parameter(defaultValue = "yyyy-MM-dd'T'HH:mm:ssZ") + @Parameter(defaultValue = "yyyy-MM-dd'T'HH:mm:ssXXX") String dateFormat; /** @@ -1454,32 +1463,26 @@ private Properties getContextProperties(MavenProject project) { * href="https://reproducible-builds.org/docs/source-date-epoch/">SOURCE_DATE_EPOCH. * *yyyy-MM-dd'T'HH:mm:ssZ + *yyyy-MM-dd'T'HH:mm:ssXXX * }
Inspired by
- * https://github.com/apache/maven-archiver/blob/a3103d99396cd8d3440b907ef932a33563225265/src/main/java/org/apache/maven/archiver/MavenArchiver.java#L765
+ * https://github.com/apache/maven-archiver/blob/7acb1db4a9754beacde3f21a69e5523ee901abd5/src/main/java/org/apache/maven/archiver/MavenArchiver.java#L755
*
* @param outputTimestamp the value of ${project.build.outputTimestamp}
(may be
* null
)
* @return the parsed timestamp, may be null
if null
input or input
* contains only 1 character
*/
- private Date parseOutputTimestamp(String outputTimestamp) throws GitCommitIdExecutionException {
+ @VisibleForTesting
+ protected static Date parseOutputTimestamp(String outputTimestamp) {
if (outputTimestamp != null
&& !outputTimestamp.trim().isEmpty()
&& outputTimestamp.chars().allMatch(Character::isDigit)) {
- return new Date(Long.parseLong(outputTimestamp) * 1000);
+ return Date.from(Instant.ofEpochSecond(Long.parseLong(outputTimestamp)));
}
if ((outputTimestamp == null) || (outputTimestamp.length() < 2)) {
// no timestamp configured
return null;
}
-
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
- try {
- return df.parse(outputTimestamp);
- } catch (ParseException pe) {
- throw new GitCommitIdExecutionException(
- "Invalid 'project.build.outputTimestamp' value '" + outputTimestamp + "'", pe);
- }
+ return new DateTime(outputTimestamp).toDate();
}
private void publishPropertiesInto(Properties propertiesToPublish, Properties propertiesTarget) {
diff --git a/src/test/java/pl/project13/maven/git/GitCommitIdMojoTest.java b/src/test/java/pl/project13/maven/git/GitCommitIdMojoTest.java
index 52fcc8b8..0686dfad 100644
--- a/src/test/java/pl/project13/maven/git/GitCommitIdMojoTest.java
+++ b/src/test/java/pl/project13/maven/git/GitCommitIdMojoTest.java
@@ -22,12 +22,19 @@
import java.io.File;
import java.io.IOException;
+import java.time.Instant;
+import java.util.Date;
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+import org.joda.time.DateTime;
import org.junit.Test;
+import org.junit.runner.RunWith;
import pl.project13.core.PropertiesFileGenerator;
/**
* Testcases to verify that the git-commit-id works properly.
*/
+@RunWith(JUnitParamsRunner.class)
public class GitCommitIdMojoTest {
@Test
public void testCraftPropertiesOutputFileWithRelativePath() throws IOException {
@@ -66,4 +73,66 @@ public void testCraftPropertiesOutputFileWithFullPath() throws IOException {
.toFile()
.getCanonicalPath());
}
+
+ /**
+ * test cases for output timestamp parsing.
+ * This timestamp is configured for Reproducible Builds' archive entries
+ * (https://maven.apache.org/guides/mini/guide-reproducible-builds.html). The value from
+ * ${project.build.outputTimestamp}
is either formatted as ISO 8601
+ * yyyy-MM-dd'T'HH:mm:ssXXX
or as an int representing seconds since the epoch (like SOURCE_DATE_EPOCH.
+ * When using ISO 8601 formatting please note that the entire expression must be entirely either
+ * in the basic format (20240215T135459+0100) or in the
+ * extended format (e.g. 2024-02-15T13:54:59+01:00).
+ * The maven plugin only supports the extended format.
+ */
+ private Object[] parametersParseOutputTimestamp() {
+ return new Object[] {
+ // long since epoch
+ new Object[] {
+ "1644689403"
+ },
+ // Date and time with timezone:
+ new Object[] {
+ "2022-02-12T15:30+00:00"
+ },
+ new Object[] {
+ "2022-02-12T15:30:45-05:00"
+ },
+ new Object[] {
+ "2022-02-12T15:30:00+00:00"
+ },
+ new Object[] {
+ "2023-11-30T09:17:06+05:30"
+ },
+ new Object[] {
+ "2024-08-15T20:45:30-03:00"
+ },
+ new Object[] {
+ "2022-02-12T15:30:00Z"
+ },
+ new Object[] {
+ "2023-11-30T09:17:06+0100"
+ },
+ // Lowercase time designator
+ new Object[] {
+ "2019-03-26t14:00Z"
+ },
+ // Lowercase UTC designator
+ new Object[] {
+ "2019-03-26T14:00z"
+ },
+ // Hours-only offset
+ new Object[] {
+ "2019-03-26T10:00-04"
+ },
+ };
+ }
+
+ @Test
+ @Parameters(method = "parametersParseOutputTimestamp")
+ public void testParseOutputTimestamp(String input) {
+ Date actual = GitCommitIdMojo.parseOutputTimestamp(input);
+ assertThat(actual).isNotNull();
+ }
}
diff --git a/src/test/java/pl/project13/maven/git/NativeAndJGitProviderTest.java b/src/test/java/pl/project13/maven/git/NativeAndJGitProviderTest.java
index f0ec603b..215c5439 100644
--- a/src/test/java/pl/project13/maven/git/NativeAndJGitProviderTest.java
+++ b/src/test/java/pl/project13/maven/git/NativeAndJGitProviderTest.java
@@ -56,8 +56,8 @@ public class NativeAndJGitProviderTest extends GitIntegrationTest {
"git.local.branch.behind",
};
- private static final String DEFAULT_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ssZ";
- private static final String ISO8601_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ssZZ";
+ private static final String DEFAULT_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ssXXX";
+ private static final String ISO8601_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ssXXX";
@Test
public void testCompareBasic() throws Exception {