This is an automated email from the ASF dual-hosted git repository. hboutemy pushed a commit to branch MARTIFACT-64 in repository https://gitbox.apache.org/repos/asf/maven-artifact-plugin.git
commit 9402feb54e5c33d0d4148670fea6abc1bbd01a48 Author: Hervé Boutemy <hbout...@apache.org> AuthorDate: Sun Apr 21 17:55:58 2024 +0200 [MARTIFACT-64] add diagnose parameter, ITs for git commit timestamp and hints on found edge cases --- src/it/git-mono/invoker.properties | 18 +++++ src/it/git-mono/pom.xml | 76 ++++++++++++++++++++ src/it/git-multi/invoker.properties | 22 ++++++ src/it/git-multi/modA/pom.xml | 31 +++++++++ src/it/git-multi/modB/pom.xml | 39 +++++++++++ src/it/git-multi/pom.xml | 80 ++++++++++++++++++++++ .../artifact/buildinfo/AbstractBuildinfoMojo.java | 50 ++++++++++++-- .../artifact/buildinfo/CheckBuildPlanMojo.java | 12 +++- 8 files changed, 322 insertions(+), 6 deletions(-) diff --git a/src/it/git-mono/invoker.properties b/src/it/git-mono/invoker.properties new file mode 100644 index 0000000..5569256 --- /dev/null +++ b/src/it/git-mono/invoker.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +invoker.goals=clean verify artifact:check-buildplan -Ddiagnose diff --git a/src/it/git-mono/pom.xml b/src/it/git-mono/pom.xml new file mode 100644 index 0000000..a6c531c --- /dev/null +++ b/src/it/git-mono/pom.xml @@ -0,0 +1,76 @@ +<?xml version='1.0' encoding='UTF-8'?> + +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.apache.maven.plugins.it</groupId> + <artifactId>git-mono</artifactId> + <version>1.0-SNAPSHOT</version> + + <description>An IT looking at a mono-module build with outputTimestamp using git commit timestamp.</description> + + <prerequisites> + <maven>3.0.5</maven> + </prerequisites> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.build.outputTimestamp>${git.commit.time}</project.build.outputTimestamp> + </properties> + + <build> + <plugins> + <plugin> + <groupId>pl.project13.maven</groupId><!-- older groupId, for version 4.xx --> + <artifactId>git-commit-id-plugin</artifactId> + <version>4.9.10</version><!-- https://github.com/git-commit-id/git-commit-id-maven-plugin?tab=readme-ov-file#plugin-compatibility-with-java --> + <executions> + <execution> + <id>resolve-git-properties</id> + <goals> + <goal>revision</goal> + </goals> + <phase>validate</phase> + <configuration> + <failOnNoGitDirectory>false</failOnNoGitDirectory> + <dateFormat>yyyy-MM-dd'T'HH:mm:ssXXX</dateFormat> + <dateFormatTimeZone>UTC</dateFormatTimeZone><!-- avoid depending on user's timezone --> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>@project.groupId@</groupId> + <artifactId>@project.artifactId@</artifactId> + <version>@project.version@</version> + <executions> + <execution> + <goals> + <goal>buildinfo</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/src/it/git-multi/invoker.properties b/src/it/git-multi/invoker.properties new file mode 100644 index 0000000..44889d3 --- /dev/null +++ b/src/it/git-multi/invoker.properties @@ -0,0 +1,22 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +invoker.goals.1=clean verify artifact:check-buildplan -Ddiagnose -Dcheck.failOnNonReproducible=false +# second invocation with check-buildplan is expected to have issue because validate phase not run, then no git-commit-it-plugin +invoker.goals.2=artifact:check-buildplan -Ddiagnose -Dcheck.failOnNonReproducible=false +# third invocation is ok because explicit validate +invoker.goals.3=validate artifact:check-buildplan -Ddiagnose -Dcheck.failOnNonReproducible=false diff --git a/src/it/git-multi/modA/pom.xml b/src/it/git-multi/modA/pom.xml new file mode 100644 index 0000000..8c86d63 --- /dev/null +++ b/src/it/git-multi/modA/pom.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.maven.plugins.it</groupId> + <artifactId>git-multi</artifactId> + <version>1.0-SNAPSHOT</version> + </parent> + + <artifactId>multi-modA</artifactId> + <name>multi-module module A</name> +</project> diff --git a/src/it/git-multi/modB/pom.xml b/src/it/git-multi/modB/pom.xml new file mode 100644 index 0000000..4201b16 --- /dev/null +++ b/src/it/git-multi/modB/pom.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.maven.plugins.it</groupId> + <artifactId>git-multi</artifactId> + <version>1.0-SNAPSHOT</version> + </parent> + + <artifactId>multi-modB</artifactId> + <name>multi-module module B</name> + + <dependencies> + <dependency> + <groupId>org.apache.maven.plugins.it</groupId> + <artifactId>multi-modA</artifactId> + <version>1.0-SNAPSHOT</version> + </dependency> + </dependencies> +</project> diff --git a/src/it/git-multi/pom.xml b/src/it/git-multi/pom.xml new file mode 100644 index 0000000..c21911a --- /dev/null +++ b/src/it/git-multi/pom.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.apache.maven.plugins.it</groupId> + <artifactId>git-multi</artifactId> + <version>1.0-SNAPSHOT</version> + <packaging>pom</packaging> + + <description>An IT looking at a multi-module build with outputTimestamp using git commit timestamp.</description> + + <prerequisites> + <maven>3.0.5</maven> + </prerequisites> + + <modules> + <module>modB</module> + <module>modA</module> + </modules> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.build.outputTimestamp>${git.commit.time}</project.build.outputTimestamp> + </properties> + + <build> + <plugins> + <plugin> + <groupId>pl.project13.maven</groupId><!-- older groupId, for version 4.xx --> + <artifactId>git-commit-id-plugin</artifactId> + <version>4.9.10</version><!-- https://github.com/git-commit-id/git-commit-id-maven-plugin?tab=readme-ov-file#plugin-compatibility-with-java --> + <executions> + <execution> + <id>resolve-git-properties</id> + <goals> + <goal>revision</goal> + </goals> + <phase>validate</phase> + <configuration> + <skipPoms>false</skipPoms><!-- default to true, which does not configure outputTimestamp for root pom --> + <failOnNoGitDirectory>false</failOnNoGitDirectory> + <dateFormat>yyyy-MM-dd'T'HH:mm:ssXXX</dateFormat> + <dateFormatTimeZone>UTC</dateFormatTimeZone><!-- avoid depending on user's timezone --> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>@project.groupId@</groupId> + <artifactId>@project.artifactId@</artifactId> + <version>@project.version@</version> + <executions> + <execution> + <goals> + <goal>buildinfo</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/src/main/java/org/apache/maven/plugins/artifact/buildinfo/AbstractBuildinfoMojo.java b/src/main/java/org/apache/maven/plugins/artifact/buildinfo/AbstractBuildinfoMojo.java index 1c6a8ac..5977cbb 100644 --- a/src/main/java/org/apache/maven/plugins/artifact/buildinfo/AbstractBuildinfoMojo.java +++ b/src/main/java/org/apache/maven/plugins/artifact/buildinfo/AbstractBuildinfoMojo.java @@ -25,8 +25,8 @@ import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.nio.file.*; -import java.text.SimpleDateFormat; import java.time.Instant; +import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -118,6 +118,14 @@ public abstract class AbstractBuildinfoMojo extends AbstractMojo { @Parameter(defaultValue = "${project.build.outputTimestamp}") private String outputTimestamp; + /** + * Diagnose {@code outputTimestamp} effective value based on execution context. + * + * @since 3.5.2 + */ + @Parameter(property = "diagnose", defaultValue = "false") + private boolean diagnose; + /** * To obtain a toolchain if possible. */ @@ -131,7 +139,7 @@ public abstract class AbstractBuildinfoMojo extends AbstractMojo { public void execute() throws MojoExecutionException { boolean mono = session.getProjects().size() == 1; - hasBadOutputTimestamp(outputTimestamp, getLog(), project, session.getProjects()); + hasBadOutputTimestamp(outputTimestamp, getLog(), project, session.getProjects(), diagnose); if (!mono) { // if module skips install and/or deploy @@ -157,18 +165,51 @@ public abstract class AbstractBuildinfoMojo extends AbstractMojo { } static boolean hasBadOutputTimestamp( - String outputTimestamp, Log log, MavenProject project, List<MavenProject> reactorProjects) { + String outputTimestamp, + Log log, + MavenProject project, + List<MavenProject> reactorProjects, + boolean diagnose) { Instant timestamp = MavenArchiver.parseBuildOutputTimestamp(outputTimestamp).orElse(null); + + if (diagnose) { + log.info("outputTimestamp = " + outputTimestamp + " => " + + ((timestamp == null) ? "disabled" : DateTimeFormatter.ISO_INSTANT.format(timestamp))); + + String projectProperty = project.getProperties().getProperty("project.build.outputTimestamp"); + String modelProperty = project.getModel().getProperties().getProperty("project.build.outputTimestamp"); + String originalModelProperty = + project.getOriginalModel().getProperties().getProperty("project.build.outputTimestamp"); + + log.info("plugin outputTimestamp parameter diagnostics:" + System.lineSeparator() + + " - plugin outputTimestamp parameter (defaultValue=\"${project.build.outputTimestamp}\") = " + + outputTimestamp + System.lineSeparator() + + " - project project.build.outputTimestamp property = " + projectProperty + + System.lineSeparator() + + " - model project.build.outputTimestamp property = " + modelProperty + + System.lineSeparator() + + " - original model project.build.outputTimestamp property = " + originalModelProperty); + } + if (timestamp == null) { log.error("Reproducible Build not activated by project.build.outputTimestamp property: " + "see https://maven.apache.org/guides/mini/guide-reproducible-builds.html"); + + String projectProperty = project.getProperties().getProperty("project.build.outputTimestamp"); + if (projectProperty != null && projectProperty.startsWith("${git.")) { + log.error("project.build.outputTimestamp = \"" + projectProperty + "\": isn't Git value set?"); + log.error("Did validate phase run and Git plugin set the value?"); + if (project.getPackaging().equals("pom")) { + log.error("if using git-commit-id-plugin, <skipPoms>false</skipPoms> may solve the issue."); + } + } return true; } if (log.isDebugEnabled()) { log.debug("project.build.outputTimestamp = \"" + outputTimestamp + "\" => " - + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(timestamp)); + + DateTimeFormatter.ISO_INSTANT.format(timestamp)); } // check if timestamp defined in a project from reactor: warn if it is not the case @@ -213,6 +254,7 @@ public abstract class AbstractBuildinfoMojo extends AbstractMojo { File rootCopy = new File(root.getBuild().getDirectory(), root.getArtifactId() + '-' + root.getVersion() + extension); try { + rootCopy.getParentFile().mkdirs(); Files.copy( aggregate.toPath(), rootCopy.toPath(), diff --git a/src/main/java/org/apache/maven/plugins/artifact/buildinfo/CheckBuildPlanMojo.java b/src/main/java/org/apache/maven/plugins/artifact/buildinfo/CheckBuildPlanMojo.java index 7a6e00f..637fd12 100644 --- a/src/main/java/org/apache/maven/plugins/artifact/buildinfo/CheckBuildPlanMojo.java +++ b/src/main/java/org/apache/maven/plugins/artifact/buildinfo/CheckBuildPlanMojo.java @@ -71,6 +71,14 @@ public class CheckBuildPlanMojo extends AbstractMojo { @Parameter(defaultValue = "${project.build.outputTimestamp}") private String outputTimestamp; + /** + * Diagnose {@code outputTimestamp} effective value based on execution context. + * + * @since 3.5.2 + */ + @Parameter(property = "diagnose", defaultValue = "false") + private boolean diagnose; + /** * Provide a plugin issues property file to override plugin's <code>not-reproducible-plugins.properties</code>. */ @@ -95,8 +103,8 @@ public class CheckBuildPlanMojo extends AbstractMojo { @Override public void execute() throws MojoExecutionException { - boolean fail = - AbstractBuildinfoMojo.hasBadOutputTimestamp(outputTimestamp, getLog(), project, session.getProjects()); + boolean fail = AbstractBuildinfoMojo.hasBadOutputTimestamp( + outputTimestamp, getLog(), project, session.getProjects(), diagnose); // TODO check maven-jar-plugin module-info.class?