diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/cleanup/AddProjectBuildOutputTimestamp.java b/rewrite-maven/src/main/java/org/openrewrite/maven/cleanup/AddProjectBuildOutputTimestamp.java index 51539b7c610..e43913a8346 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/cleanup/AddProjectBuildOutputTimestamp.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/cleanup/AddProjectBuildOutputTimestamp.java @@ -30,10 +30,13 @@ @EqualsAndHashCode(callSuper = false) public class AddProjectBuildOutputTimestamp extends Recipe { + // DOS/ZIP timestamps have 2-second resolution, so this is the first representable instant after the 1980 epoch + private static final String EARLIEST_ZIP_COMPATIBLE_TIMESTAMP = "1980-01-01T00:00:02Z"; + @Option(displayName = "Timestamp", description = "ISO 8601 timestamp, integer seconds since the epoch, or property reference such as " + - "`${git.commit.author.time}`. Defaults to `1980-01-01T00:00:00Z`, the earliest value " + - "the ZIP format can represent.", + "`${git.commit.author.time}`. Defaults to `1980-01-01T00:00:02Z`, the earliest value " + + "accepted by Maven's ZIP-producing toolchain.", example = "2024-01-01T00:00:00Z", required = false) @Nullable @@ -56,7 +59,7 @@ public String getDescription() { public List getRecipeList() { return singletonList(new AddProperty( "project.build.outputTimestamp", - timestamp == null ? "1980-01-01T00:00:00Z" : timestamp, + timestamp == null ? EARLIEST_ZIP_COMPATIBLE_TIMESTAMP : timestamp, true, false)); } diff --git a/rewrite-maven/src/main/resources/META-INF/rewrite/examples.yml b/rewrite-maven/src/main/resources/META-INF/rewrite/examples.yml index 86f744f9ff8..63960907744 100644 --- a/rewrite-maven/src/main/resources/META-INF/rewrite/examples.yml +++ b/rewrite-maven/src/main/resources/META-INF/rewrite/examples.yml @@ -2689,7 +2689,7 @@ examples: my-app 1 - 1980-01-01T00:00:00Z + 1980-01-01T00:00:02Z UTF-8 UTF-8 @@ -3255,7 +3255,7 @@ examples: my-app 1 - 1980-01-01T00:00:00Z + 1980-01-01T00:00:02Z path: pom.xml diff --git a/rewrite-maven/src/main/resources/META-INF/rewrite/recipes.csv b/rewrite-maven/src/main/resources/META-INF/rewrite/recipes.csv index de6d9247c45..70f8ddc22ed 100644 --- a/rewrite-maven/src/main/resources/META-INF/rewrite/recipes.csv +++ b/rewrite-maven/src/main/resources/META-INF/rewrite/recipes.csv @@ -78,7 +78,7 @@ maven,org.openrewrite:rewrite-maven,org.openrewrite.maven.UpgradeToModelVersion4 maven,org.openrewrite:rewrite-maven,org.openrewrite.maven.UpgradeTransitiveDependencyVersion,Upgrade transitive Maven dependencies,"Upgrades the version of a transitive dependency in a Maven pom file. Leaves direct dependencies unmodified. When the transitive dependency's version is already governed by a plain `` entry in the project, that entry is upgraded in place rather than adding a duplicate; otherwise (including a version supplied by an imported BOM) a new managed dependency is added. Can be paired with the regular Upgrade Dependency Version recipe to upgrade a dependency everywhere, regardless of whether it is direct or transitive.",1,,Maven,,Recipes to search and transform [Apache Maven](https://maven.apache.org/) POMs.,"[{""name"":""groupId"",""type"":""String"",""displayName"":""Group"",""description"":""The first part of a dependency coordinate 'org.apache.logging.log4j:ARTIFACT_ID:VERSION'."",""example"":""org.apache.logging.log4j"",""required"":true},{""name"":""artifactId"",""type"":""String"",""displayName"":""Artifact"",""description"":""The second part of a dependency coordinate 'org.apache.logging.log4j:log4j-bom:VERSION'."",""example"":""log4j-bom"",""required"":true},{""name"":""version"",""type"":""String"",""displayName"":""Version"",""description"":""An exact version number or node-style semver selector used to select the version number."",""example"":""latest.release"",""required"":true},{""name"":""scope"",""type"":""String"",""displayName"":""Scope"",""description"":""An optional scope to use for the dependency management tag."",""example"":""import"",""valid"":[""import"",""runtime"",""provided"",""test""]},{""name"":""type"",""type"":""String"",""displayName"":""Type"",""description"":""An optional type to use for the dependency management tag."",""example"":""pom"",""valid"":[""jar"",""pom"",""war""]},{""name"":""classifier"",""type"":""String"",""displayName"":""Classifier"",""description"":""An optional classifier to use for the dependency management tag"",""example"":""test""},{""name"":""versionPattern"",""type"":""String"",""displayName"":""Version pattern"",""description"":""Allows version selection to be extended beyond the original Node Semver semantics. So for example,Setting 'version' to \""25-29\"" can be paired with a metadata pattern of \""-jre\"" to select 29.0-jre"",""example"":""-jre""},{""name"":""releasesOnly"",""type"":""Boolean"",""displayName"":""Releases only"",""description"":""Whether to exclude snapshots from consideration when using a semver selector""},{""name"":""onlyIfUsing"",""type"":""String"",""displayName"":""Only if using glob expression for group:artifact"",""description"":""Only add managed dependencies to projects having a dependency matching the expression."",""example"":""org.apache.logging.log4j:log4j*""},{""name"":""addToRootPom"",""type"":""Boolean"",""displayName"":""Add to the root pom"",""description"":""Add to the root pom where root is the eldest parent of the pom within the source set.""},{""name"":""because"",""type"":""String"",""displayName"":""Because"",""description"":""The reason for upgrading the transitive dependency. This will be added as an XML comment preceding the managed dependency."",""example"":""CVE-2021-1234""}]","[{""name"":""org.openrewrite.maven.table.MavenMetadataFailures"",""displayName"":""Maven metadata failures"",""instanceName"":""Maven metadata failures"",""description"":""Attempts to resolve maven metadata that failed."",""columns"":[{""name"":""group"",""type"":""String"",""displayName"":""Group id"",""description"":""The groupId of the artifact for which the metadata download failed.""},{""name"":""artifactId"",""type"":""String"",""displayName"":""Artifact id"",""description"":""The artifactId of the artifact for which the metadata download failed.""},{""name"":""version"",""type"":""String"",""displayName"":""Version"",""description"":""The version of the artifact for which the metadata download failed.""},{""name"":""mavenRepositoryUri"",""type"":""String"",""displayName"":""Maven repository"",""description"":""The URL of the Maven repository that the metadata download failed on.""},{""name"":""snapshots"",""type"":""String"",""displayName"":""Snapshots"",""description"":""Does the repository support snapshots.""},{""name"":""releases"",""type"":""String"",""displayName"":""Releases"",""description"":""Does the repository support releases.""},{""name"":""failure"",""type"":""String"",""displayName"":""Failure"",""description"":""The reason the metadata download failed.""}]}]" maven,org.openrewrite:rewrite-maven,org.openrewrite.maven.UseMavenCompilerPluginReleaseConfiguration,Use Maven compiler plugin release configuration,"Replaces any explicit `source` or `target` configuration (if present) on the `maven-compiler-plugin` with `release`, and updates the `release` value if needed. When `testSource` or `testTarget` differ from the main version, introduces `testRelease`. Will not downgrade the Java version if the current version is higher. Also removes stale `maven.compiler.source`, `maven.compiler.target`, `maven.compiler.testSource`, and `maven.compiler.testTarget` properties that are no longer referenced.",1,,Maven,,Recipes to search and transform [Apache Maven](https://maven.apache.org/) POMs.,"[{""name"":""releaseVersion"",""type"":""Integer"",""displayName"":""Release version"",""description"":""The new value for the release configuration. This recipe prefers ${java.version} if defined."",""example"":""11"",""required"":true}]", maven,org.openrewrite:rewrite-maven,org.openrewrite.maven.UseParentInference,Use Maven 4 parent inference,"Maven 4.1.0 supports automatic parent version inference when using a relative path. This recipe simplifies parent declarations by using the shorthand `` form when the parent is in the default location (`..`), removing the explicit ``, ``, ``, and `` elements. Maven automatically infers these values from the parent POM.",1,,Maven,,Recipes to search and transform [Apache Maven](https://maven.apache.org/) POMs.,, -maven,org.openrewrite:rewrite-maven,org.openrewrite.maven.cleanup.AddProjectBuildOutputTimestamp,Add `project.build.outputTimestamp` for reproducible builds,"Adds the `project.build.outputTimestamp` property, which Maven uses to make build outputs reproducible by stamping archive entries with a fixed timestamp instead of the current time. An existing value is preserved. See [Configuring for Reproducible Builds](https://maven.apache.org/guides/mini/guide-reproducible-builds.html).",2,Cleanup,Maven,,Recipes to search and transform [Apache Maven](https://maven.apache.org/) POMs.,"[{""name"":""timestamp"",""type"":""String"",""displayName"":""Timestamp"",""description"":""ISO 8601 timestamp, integer seconds since the epoch, or property reference such as `${git.commit.author.time}`. Defaults to `1980-01-01T00:00:00Z`, the earliest value the ZIP format can represent."",""example"":""2024-01-01T00:00:00Z""}]", +maven,org.openrewrite:rewrite-maven,org.openrewrite.maven.cleanup.AddProjectBuildOutputTimestamp,Add `project.build.outputTimestamp` for reproducible builds,"Adds the `project.build.outputTimestamp` property, which Maven uses to make build outputs reproducible by stamping archive entries with a fixed timestamp instead of the current time. An existing value is preserved. See [Configuring for Reproducible Builds](https://maven.apache.org/guides/mini/guide-reproducible-builds.html).",2,Cleanup,Maven,,Recipes to search and transform [Apache Maven](https://maven.apache.org/) POMs.,"[{""name"":""timestamp"",""type"":""String"",""displayName"":""Timestamp"",""description"":""ISO 8601 timestamp, integer seconds since the epoch, or property reference such as `${git.commit.author.time}`. Defaults to `1980-01-01T00:00:02Z`, the earliest value accepted by Maven's ZIP-producing toolchain."",""example"":""2024-01-01T00:00:00Z""}]", maven,org.openrewrite:rewrite-maven,org.openrewrite.maven.cleanup.DependencyManagementDependencyRequiresVersion,Dependency management dependencies should have a version,"If they don't have a version, they can't possibly affect dependency resolution anywhere, and can be safely removed.",1,Cleanup,Maven,,Recipes to search and transform [Apache Maven](https://maven.apache.org/) POMs.,, maven,org.openrewrite:rewrite-maven,org.openrewrite.maven.cleanup.ExplicitDependencyVersion,Add explicit dependency versions,"Add explicit dependency versions to POMs for reproducibility, as the `LATEST` and `RELEASE` version keywords are deprecated.",1,Cleanup,Maven,,Recipes to search and transform [Apache Maven](https://maven.apache.org/) POMs.,,"[{""name"":""org.openrewrite.maven.table.MavenMetadataFailures"",""displayName"":""Maven metadata failures"",""instanceName"":""Maven metadata failures"",""description"":""Attempts to resolve maven metadata that failed."",""columns"":[{""name"":""group"",""type"":""String"",""displayName"":""Group id"",""description"":""The groupId of the artifact for which the metadata download failed.""},{""name"":""artifactId"",""type"":""String"",""displayName"":""Artifact id"",""description"":""The artifactId of the artifact for which the metadata download failed.""},{""name"":""version"",""type"":""String"",""displayName"":""Version"",""description"":""The version of the artifact for which the metadata download failed.""},{""name"":""mavenRepositoryUri"",""type"":""String"",""displayName"":""Maven repository"",""description"":""The URL of the Maven repository that the metadata download failed on.""},{""name"":""snapshots"",""type"":""String"",""displayName"":""Snapshots"",""description"":""Does the repository support snapshots.""},{""name"":""releases"",""type"":""String"",""displayName"":""Releases"",""description"":""Does the repository support releases.""},{""name"":""failure"",""type"":""String"",""displayName"":""Failure"",""description"":""The reason the metadata download failed.""}]}]" maven,org.openrewrite:rewrite-maven,org.openrewrite.maven.cleanup.ExplicitPluginGroupId,Add explicit `groupId` to Maven plugins,Add the default `org.apache.maven.plugins` to plugins for clarity.,1,Cleanup,Maven,,Recipes to search and transform [Apache Maven](https://maven.apache.org/) POMs.,, diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/ReproducibleBuildsTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/ReproducibleBuildsTest.java index 5f90e054afd..36cb4962c2f 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/ReproducibleBuildsTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/ReproducibleBuildsTest.java @@ -48,7 +48,7 @@ void appliesEncodingAndOutputTimestamp() { my-app 1 - 1980-01-01T00:00:00Z + 1980-01-01T00:00:02Z UTF-8 UTF-8 diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/cleanup/AddProjectBuildOutputTimestampTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/cleanup/AddProjectBuildOutputTimestampTest.java index 70f6bc15b45..60342bfac2e 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/cleanup/AddProjectBuildOutputTimestampTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/cleanup/AddProjectBuildOutputTimestampTest.java @@ -47,7 +47,7 @@ void addsDefaultTimestamp() { my-app 1 - 1980-01-01T00:00:00Z + 1980-01-01T00:00:02Z """ @@ -120,7 +120,7 @@ void addsToExistingPropertiesBlock() { 1 21 - 1980-01-01T00:00:00Z + 1980-01-01T00:00:02Z """