Skip to content

Commit 6ab02b1

Browse files
authored
Merge pull request #699 from git-commit-id/674
#674: change timeformat from RFC822 to ISO 8601 to support maven's reproducible build feature
2 parents 4c638aa + fcd414d commit 6ab02b1

File tree

5 files changed

+96
-24
lines changed

5 files changed

+96
-24
lines changed

.github/workflows/default-tests.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
needs: checkstyle
3232
strategy:
3333
matrix:
34-
java_version: ['11', '12', '13', '14', '15', '16', '17', '18', '19', '20']
34+
java_version: ['11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21']
3535

3636
steps:
3737
- uses: actions/checkout@v4
@@ -59,7 +59,7 @@ jobs:
5959
strategy:
6060
matrix:
6161
java_version: ['11']
62-
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']
62+
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']
6363

6464
steps:
6565
- uses: actions/checkout@v4

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@
397397
<dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
398398
<generateGitPropertiesFile>true</generateGitPropertiesFile>
399399
<generateGitPropertiesFilename>target/testing.properties</generateGitPropertiesFilename>
400-
<dateFormat>yyyy-MM-dd'T'HH:mm:ssZ</dateFormat>
400+
<!-- <dateFormat>yyyy-MM-dd'T'HH:mm:ssXXX</dateFormat> -->
401401
<dateFormatTimeZone>GMT-08:00</dateFormatTimeZone>
402402
<useNativeGit>false</useNativeGit>
403403
<abbrevLength>7</abbrevLength>

src/main/java/pl/project13/maven/git/GitCommitIdMojo.java

+22-19
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818

1919
package pl.project13.maven.git;
2020

21+
import com.google.common.annotations.VisibleForTesting;
2122
import java.io.File;
2223
import java.nio.charset.Charset;
2324
import java.nio.charset.StandardCharsets;
24-
import java.text.DateFormat;
25-
import java.text.ParseException;
2625
import java.text.SimpleDateFormat;
26+
import java.time.Instant;
2727
import java.util.Collections;
2828
import java.util.Date;
2929
import java.util.List;
@@ -44,6 +44,7 @@
4444
import org.apache.maven.plugins.annotations.Parameter;
4545
import org.apache.maven.project.MavenProject;
4646
import org.apache.maven.settings.Settings;
47+
import org.joda.time.DateTime;
4748
import org.sonatype.plexus.build.incremental.BuildContext;
4849
import pl.project13.core.CommitIdGenerationMode;
4950
import pl.project13.core.CommitIdPropertiesOutputFormat;
@@ -497,20 +498,28 @@ public class GitCommitIdMojo extends AbstractMojo {
497498
* represents dates or times exported by this plugin (e.g. {@code git.commit.time}, {@code
498499
* git.build.time}). It should be a valid {@link SimpleDateFormat} string.
499500
*
500-
* <p>The current dateFormat is set to match maven's default {@code yyyy-MM-dd'T'HH:mm:ssZ}.
501-
* Please note that in previous versions (2.2.0 - 2.2.2) the default dateFormat was set to: {@code
502-
* dd.MM.yyyy '@' HH:mm:ss z}. However the {@code RFC 822 time zone} seems to give a more reliable
503-
* option in parsing the date and it's being used in maven as default.
501+
* <p>The current dateFormat will be formatted as ISO 8601
502+
* {@code yyyy-MM-dd'T'HH:mm:ssXXX} and therefore can be used as input to maven's
503+
* <a href="https://maven.apache.org/guides/mini/guide-reproducible-builds.html">
504+
* reproducible build</a> feature.
505+
*
506+
* Please note that in previous versions
507+
* (2.2.2 - 7.0.1) the default format was set to {@code yyyy-MM-dd'T'HH:mm:ssZ}
508+
* which produces a {@code RFC 822 time zone}. While such format gives reliable
509+
* options in parsing the date, it does not comply with the requirements of
510+
* the reproducible build feature.
511+
* (2.2.0 - 2.2.2) the default dateFormat was set to: {@code
512+
* dd.MM.yyyy '@' HH:mm:ss z}.
504513
*
505514
* <p>Example:
506515
*
507516
* <pre>{@code
508-
* <dateFormat>yyyy-MM-dd'T'HH:mm:ssZ</dateFormat>
517+
* <dateFormat>yyyy-MM-dd'T'HH:mm:ssXXX</dateFormat>
509518
* }</pre>
510519
*
511520
* @since 2.2.0
512521
*/
513-
@Parameter(defaultValue = "yyyy-MM-dd'T'HH:mm:ssZ")
522+
@Parameter(defaultValue = "yyyy-MM-dd'T'HH:mm:ssXXX")
514523
String dateFormat;
515524

516525
/**
@@ -1454,32 +1463,26 @@ private Properties getContextProperties(MavenProject project) {
14541463
* href="https://reproducible-builds.org/docs/source-date-epoch/">SOURCE_DATE_EPOCH</a>.
14551464
*
14561465
* <p>Inspired by
1457-
* https://github.com/apache/maven-archiver/blob/a3103d99396cd8d3440b907ef932a33563225265/src/main/java/org/apache/maven/archiver/MavenArchiver.java#L765
1466+
* https://github.com/apache/maven-archiver/blob/7acb1db4a9754beacde3f21a69e5523ee901abd5/src/main/java/org/apache/maven/archiver/MavenArchiver.java#L755
14581467
*
14591468
* @param outputTimestamp the value of <code>${project.build.outputTimestamp}</code> (may be
14601469
* <code>null</code>)
14611470
* @return the parsed timestamp, may be <code>null</code> if <code>null</code> input or input
14621471
* contains only 1 character
14631472
*/
1464-
private Date parseOutputTimestamp(String outputTimestamp) throws GitCommitIdExecutionException {
1473+
@VisibleForTesting
1474+
protected static Date parseOutputTimestamp(String outputTimestamp) {
14651475
if (outputTimestamp != null
14661476
&& !outputTimestamp.trim().isEmpty()
14671477
&& outputTimestamp.chars().allMatch(Character::isDigit)) {
1468-
return new Date(Long.parseLong(outputTimestamp) * 1000);
1478+
return Date.from(Instant.ofEpochSecond(Long.parseLong(outputTimestamp)));
14691479
}
14701480

14711481
if ((outputTimestamp == null) || (outputTimestamp.length() < 2)) {
14721482
// no timestamp configured
14731483
return null;
14741484
}
1475-
1476-
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
1477-
try {
1478-
return df.parse(outputTimestamp);
1479-
} catch (ParseException pe) {
1480-
throw new GitCommitIdExecutionException(
1481-
"Invalid 'project.build.outputTimestamp' value '" + outputTimestamp + "'", pe);
1482-
}
1485+
return new DateTime(outputTimestamp).toDate();
14831486
}
14841487

14851488
private void publishPropertiesInto(Properties propertiesToPublish, Properties propertiesTarget) {

src/test/java/pl/project13/maven/git/GitCommitIdMojoTest.java

+69
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,19 @@
2222

2323
import java.io.File;
2424
import java.io.IOException;
25+
import java.time.Instant;
26+
import java.util.Date;
27+
import junitparams.JUnitParamsRunner;
28+
import junitparams.Parameters;
29+
import org.joda.time.DateTime;
2530
import org.junit.Test;
31+
import org.junit.runner.RunWith;
2632
import pl.project13.core.PropertiesFileGenerator;
2733

2834
/**
2935
* Testcases to verify that the git-commit-id works properly.
3036
*/
37+
@RunWith(JUnitParamsRunner.class)
3138
public class GitCommitIdMojoTest {
3239
@Test
3340
public void testCraftPropertiesOutputFileWithRelativePath() throws IOException {
@@ -66,4 +73,66 @@ public void testCraftPropertiesOutputFileWithFullPath() throws IOException {
6673
.toFile()
6774
.getCanonicalPath());
6875
}
76+
77+
/**
78+
* test cases for output timestamp parsing.
79+
* This timestamp is configured for Reproducible Builds' archive entries
80+
* (https://maven.apache.org/guides/mini/guide-reproducible-builds.html). The value from <code>
81+
* ${project.build.outputTimestamp}</code> is either formatted as ISO 8601 <code>
82+
* yyyy-MM-dd'T'HH:mm:ssXXX</code> or as an int representing seconds since the epoch (like <a
83+
* href="https://reproducible-builds.org/docs/source-date-epoch/">SOURCE_DATE_EPOCH</a>.
84+
* When using ISO 8601 formatting please note that the entire expression must be entirely either
85+
* in the basic format (20240215T135459+0100) or in the
86+
* extended format (e.g. 2024-02-15T13:54:59+01:00).
87+
* The maven plugin only supports the extended format.
88+
*/
89+
private Object[] parametersParseOutputTimestamp() {
90+
return new Object[] {
91+
// long since epoch
92+
new Object[] {
93+
"1644689403"
94+
},
95+
// Date and time with timezone:
96+
new Object[] {
97+
"2022-02-12T15:30+00:00"
98+
},
99+
new Object[] {
100+
"2022-02-12T15:30:45-05:00"
101+
},
102+
new Object[] {
103+
"2022-02-12T15:30:00+00:00"
104+
},
105+
new Object[] {
106+
"2023-11-30T09:17:06+05:30"
107+
},
108+
new Object[] {
109+
"2024-08-15T20:45:30-03:00"
110+
},
111+
new Object[] {
112+
"2022-02-12T15:30:00Z"
113+
},
114+
new Object[] {
115+
"2023-11-30T09:17:06+0100"
116+
},
117+
// Lowercase time designator
118+
new Object[] {
119+
"2019-03-26t14:00Z"
120+
},
121+
// Lowercase UTC designator
122+
new Object[] {
123+
"2019-03-26T14:00z"
124+
},
125+
// Hours-only offset
126+
new Object[] {
127+
"2019-03-26T10:00-04"
128+
},
129+
};
130+
}
131+
132+
@Test
133+
@Parameters(method = "parametersParseOutputTimestamp")
134+
public void testParseOutputTimestamp(String input) {
135+
Date actual = GitCommitIdMojo.parseOutputTimestamp(input);
136+
assertThat(actual).isNotNull();
137+
}
69138
}

src/test/java/pl/project13/maven/git/NativeAndJGitProviderTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ public class NativeAndJGitProviderTest extends GitIntegrationTest {
5656
"git.local.branch.behind",
5757
};
5858

59-
private static final String DEFAULT_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ssZ";
60-
private static final String ISO8601_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ssZZ";
59+
private static final String DEFAULT_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ssXXX";
60+
private static final String ISO8601_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ssXXX";
6161

6262
@Test
6363
public void testCompareBasic() throws Exception {

0 commit comments

Comments
 (0)