You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ol...@apache.org on 2024/04/30 21:01:31 UTC

(maven-build-cache-extension) branch master updated: [MBUILDCACHE-90] Mandatory clean option to store in cache (#103)

This is an automated email from the ASF dual-hosted git repository.

olamy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-build-cache-extension.git


The following commit(s) were added to refs/heads/master by this push:
     new 8e3dad7  [MBUILDCACHE-90] Mandatory clean option to store in cache (#103)
8e3dad7 is described below

commit 8e3dad72f0a0a8b38778ca7faba1bb769adb3175
Author: Kévin Buntrock <ke...@kleegroup.com>
AuthorDate: Tue Apr 30 23:01:25 2024 +0200

    [MBUILDCACHE-90] Mandatory clean option to store in cache (#103)
---
 .../BuildCacheMojosExecutionStrategy.java          |   5 +
 .../apache/maven/buildcache/xml/CacheConfig.java   |   5 +
 .../maven/buildcache/xml/CacheConfigImpl.java      |   6 +
 src/main/mdo/build-cache-config.mdo                |   6 +
 src/site/markdown/parameters.md                    |   1 +
 .../maven/buildcache/its/MandatoryCleanTest.java   | 156 +++++++++++++++++++++
 .../apache/maven/buildcache/util/LogFileUtils.java |  17 +++
 .../projects/mandatory-clean/.mvn/extensions.xml   |  25 ++++
 .../.mvn/maven-build-cache-config.xml              |  28 ++++
 .../projects/mandatory-clean/forked-module/pom.xml |  56 ++++++++
 .../maven/buildcache/ForkedExecutionClass.java     |  24 ++++
 .../mandatory-clean/non-forked-module/pom.xml      |  32 +++++
 .../java/org/apache/maven/buildcache/Test.java     |  24 ++++
 src/test/projects/mandatory-clean/pom.xml          |  37 +++++
 14 files changed, 422 insertions(+)

diff --git a/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java b/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java
index e35981d..7726312 100644
--- a/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java
+++ b/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java
@@ -150,6 +150,11 @@ public class BuildCacheMojosExecutionStrategy implements MojosExecutionStrategy
             if (cacheState == INITIALIZED && (!result.isSuccess() || !restored)) {
                 if (cacheConfig.isSkipSave()) {
                     LOGGER.info("Cache saving is disabled.");
+                } else if (cacheConfig.isMandatoryClean()
+                        && lifecyclePhasesHelper
+                                .getCleanSegment(project, mojoExecutions)
+                                .isEmpty()) {
+                    LOGGER.info("Cache storing is skipped since there was no \"clean\" phase.");
                 } else {
                     final Map<String, MojoExecutionEvent> executionEvents = mojoListener.getProjectExecutions(project);
                     cacheController.save(result, mojoExecutions, executionEvents);
diff --git a/src/main/java/org/apache/maven/buildcache/xml/CacheConfig.java b/src/main/java/org/apache/maven/buildcache/xml/CacheConfig.java
index 797e1f4..3bcfa23 100644
--- a/src/main/java/org/apache/maven/buildcache/xml/CacheConfig.java
+++ b/src/main/java/org/apache/maven/buildcache/xml/CacheConfig.java
@@ -139,4 +139,9 @@ public interface CacheConfig {
      * Flag to disable cache saving
      */
     boolean isSkipSave();
+
+    /**
+     * Flag to save in cache only if a build went through the clean lifecycle
+     */
+    boolean isMandatoryClean();
 }
diff --git a/src/main/java/org/apache/maven/buildcache/xml/CacheConfigImpl.java b/src/main/java/org/apache/maven/buildcache/xml/CacheConfigImpl.java
index 8c98afb..208c92d 100644
--- a/src/main/java/org/apache/maven/buildcache/xml/CacheConfigImpl.java
+++ b/src/main/java/org/apache/maven/buildcache/xml/CacheConfigImpl.java
@@ -92,6 +92,7 @@ public class CacheConfigImpl implements org.apache.maven.buildcache.xml.CacheCon
     public static final String LAZY_RESTORE_PROPERTY_NAME = "maven.build.cache.lazyRestore";
     public static final String RESTORE_GENERATED_SOURCES_PROPERTY_NAME = "maven.build.cache.restoreGeneratedSources";
     public static final String ALWAYS_RUN_PLUGINS = "maven.build.cache.alwaysRunPlugins";
+    public static final String MANDATORY_CLEAN = "maven.build.cache.mandatoryClean";
 
     /**
      * Flag to control if we should skip lookup for cached artifacts globally or for a particular project even if
@@ -513,6 +514,11 @@ public class CacheConfigImpl implements org.apache.maven.buildcache.xml.CacheCon
         return getProperty(SKIP_SAVE, false);
     }
 
+    @Override
+    public boolean isMandatoryClean() {
+        return getProperty(MANDATORY_CLEAN, getConfiguration().isMandatoryClean());
+    }
+
     @Override
     public String getId() {
         checkInitializedState();
diff --git a/src/main/mdo/build-cache-config.mdo b/src/main/mdo/build-cache-config.mdo
index 65f2ec7..9ff96c8 100644
--- a/src/main/mdo/build-cache-config.mdo
+++ b/src/main/mdo/build-cache-config.mdo
@@ -194,6 +194,12 @@ under the License.
                         TODO: not implemented
                     </description>
                 </field>
+                <field>
+                    <name>mandatoryClean</name>
+                    <type>boolean</type>
+                    <defaultValue>false</defaultValue>
+                    <description>Enable the cache storing ability only if a build went through the clean lifecycle.</description>
+                </field>
                 <field>
                     <name>multiModule</name>
                     <association>
diff --git a/src/site/markdown/parameters.md b/src/site/markdown/parameters.md
index abb2fe5..76aed1a 100644
--- a/src/site/markdown/parameters.md
+++ b/src/site/markdown/parameters.md
@@ -37,6 +37,7 @@ This document contains various configuration parameters supported by the cache e
 | `-Dmaven.build.cache.alwaysRunPlugins=<list of plugins>`   | Comma separated list of plugins to always run regardless of cache state. An example: `maven-deploy-plugin:*,maven-install-plugin:install` | Remote cache setup/tuning/troubleshooting                                          |
 | `-Dmaven.build.cache.skipCache=(true/false)`               | Skip looking up artifacts in caches. Does not affect writing artifacts to caches, disables only reading when set to `true`               | May be used to trigger a forced rebuild when matching artifacts do exist in caches |
 | `-Dmaven.build.cache.skipSave=(true/false)`            | Skip writing build result in caches. Does not affect reading from the cache.               | Configuring MR builds to benefits from the cache, but restricting writes to the `master` branch |
+| `-Dmaven.build.cache.mandatoryClean=(true/false)`          | Enable or disable the necessity to execute the `clean` phase in order to store the build result in cache                                  | Reducing the risk to save "wrong" files in cache in a local dev environnement      |
 
 ### Project-level properties
 
diff --git a/src/test/java/org/apache/maven/buildcache/its/MandatoryCleanTest.java b/src/test/java/org/apache/maven/buildcache/its/MandatoryCleanTest.java
new file mode 100644
index 0000000..72ded2c
--- /dev/null
+++ b/src/test/java/org/apache/maven/buildcache/its/MandatoryCleanTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+package org.apache.maven.buildcache.its;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.maven.buildcache.its.junit.IntegrationTest;
+import org.apache.maven.buildcache.util.LogFileUtils;
+import org.apache.maven.buildcache.xml.CacheConfigImpl;
+import org.apache.maven.it.VerificationException;
+import org.apache.maven.it.Verifier;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.maven.buildcache.xml.CacheConfigImpl.CACHE_LOCATION_PROPERTY_NAME;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * Test the "mandatoryClean" parameter : saving in cache should be done only if a clean phase has been executed.
+ */
+@IntegrationTest("src/test/projects/mandatory-clean")
+public class MandatoryCleanTest {
+
+    private static final String MODULE_NAME_1 = "org.apache.maven.caching.test.simple:non-forked-module";
+    private static final String MODULE_NAME_2 = "org.apache.maven.caching.test.simple:forked-module";
+    private static final String CACHE_BUILD_LOG = "Found cached build, restoring %s from cache";
+
+    @Test
+    void simple(Verifier verifier) throws VerificationException, IOException {
+
+        verifier.setAutoclean(false);
+        Path tempDirectory = Files.createTempDirectory("simple-mandatory-clean");
+        verifier.getCliOptions().clear();
+        verifier.addCliOption("-D" + CACHE_LOCATION_PROPERTY_NAME + "=" + tempDirectory.toAbsolutePath());
+
+        verifier.setLogFileName("../log-1.txt");
+        verifier.executeGoal("verify");
+        verifier.verifyErrorFreeLog();
+        List<String> cacheSkippedBuild1 = LogFileUtils.findLinesContainingTextsInLogs(
+                verifier, "Cache storing is skipped since there was no \"clean\" phase.");
+        Assertions.assertEquals(2, cacheSkippedBuild1.size(), "Expected 2 skipped module caching");
+
+        assertThrows(
+                VerificationException.class,
+                () -> verifier.verifyTextInLog(String.format(CACHE_BUILD_LOG, MODULE_NAME_1)),
+                "not expected to be loaded from the cache");
+        assertThrows(
+                VerificationException.class,
+                () -> verifier.verifyTextInLog(String.format(CACHE_BUILD_LOG, MODULE_NAME_2)),
+                "not expected to be loaded from the cache");
+
+        verifier.setLogFileName("../log-2.txt");
+        verifier.executeGoals(Arrays.asList("clean", "verify"));
+        verifier.verifyErrorFreeLog();
+        List<String> cacheSkippedBuild2 = LogFileUtils.findLinesContainingTextsInLogs(
+                verifier, "Cache storing is skipped since there was no \"clean\" phase.");
+        Assertions.assertEquals(0, cacheSkippedBuild2.size(), "Expected 2 skipped module caching");
+        assertThrows(
+                VerificationException.class,
+                () -> verifier.verifyTextInLog(String.format(CACHE_BUILD_LOG, MODULE_NAME_1)),
+                "not expected to be loaded from the cache");
+        assertThrows(
+                VerificationException.class,
+                () -> verifier.verifyTextInLog(String.format(CACHE_BUILD_LOG, MODULE_NAME_2)),
+                "not expected to be loaded from the cache");
+
+        verifier.setLogFileName("../log-3.txt");
+        verifier.executeGoal("verify");
+        verifier.verifyErrorFreeLog();
+        List<String> cacheSkippedBuild3 = LogFileUtils.findLinesContainingTextsInLogs(
+                verifier, "Cache storing is skipped since there was no \"clean\" phase.");
+        Assertions.assertEquals(0, cacheSkippedBuild3.size(), "loading from cache, no more caching required");
+        // Expect to find and restore cached project
+        verifier.verifyTextInLog(String.format(CACHE_BUILD_LOG, MODULE_NAME_1));
+        verifier.verifyTextInLog(String.format(CACHE_BUILD_LOG, MODULE_NAME_2));
+    }
+
+    @Test
+    void disabledViaProperty(Verifier verifier) throws VerificationException {
+
+        verifier.setAutoclean(false);
+
+        verifier.setLogFileName("../log-1.txt");
+        verifier.executeGoal("verify");
+        verifier.verifyErrorFreeLog();
+        List<String> cacheSkippedBuild1 = LogFileUtils.findLinesContainingTextsInLogs(
+                verifier, "Cache storing is skipped since there was no \"clean\" phase.");
+        Assertions.assertEquals(2, cacheSkippedBuild1.size(), "Expected 2 skipped module caching");
+
+        assertThrows(
+                VerificationException.class,
+                () -> verifier.verifyTextInLog(String.format(CACHE_BUILD_LOG, MODULE_NAME_1)),
+                "not expected to be loaded from the cache");
+        assertThrows(
+                VerificationException.class,
+                () -> verifier.verifyTextInLog(String.format(CACHE_BUILD_LOG, MODULE_NAME_2)),
+                "not expected to be loaded from the cache");
+
+        verifier.setLogFileName("../log-2.txt");
+        verifier.getCliOptions().clear();
+        // With "true", we do not change the initially expected behaviour
+        verifier.addCliOption("-D" + CacheConfigImpl.MANDATORY_CLEAN + "=true");
+        verifier.executeGoal("verify");
+        verifier.verifyErrorFreeLog();
+        List<String> cacheSkippedBuild2 = LogFileUtils.findLinesContainingTextsInLogs(
+                verifier, "Cache storing is skipped since there was no \"clean\" phase.");
+        Assertions.assertEquals(2, cacheSkippedBuild2.size(), "Expected 2 skipped module caching");
+
+        assertThrows(
+                VerificationException.class,
+                () -> verifier.verifyTextInLog(String.format(CACHE_BUILD_LOG, MODULE_NAME_1)),
+                "not expected to be loaded from the cache");
+        assertThrows(
+                VerificationException.class,
+                () -> verifier.verifyTextInLog(String.format(CACHE_BUILD_LOG, MODULE_NAME_2)),
+                "not expected to be loaded from the cache");
+
+        // With "false", we remove the need for the clean phase
+        verifier.getCliOptions().clear();
+        verifier.addCliOption("-D" + CacheConfigImpl.MANDATORY_CLEAN + "=false");
+        verifier.setLogFileName("../log-3.txt");
+        verifier.executeGoal("verify");
+        verifier.verifyErrorFreeLog();
+        List<String> cacheSkippedBuild3 = LogFileUtils.findLinesContainingTextsInLogs(
+                verifier, "Cache storing is skipped since there was no \"clean\" phase.");
+        Assertions.assertEquals(0, cacheSkippedBuild3.size(), "Expected 2 skipped module caching");
+        assertThrows(
+                VerificationException.class,
+                () -> verifier.verifyTextInLog(String.format(CACHE_BUILD_LOG, MODULE_NAME_1)),
+                "not expected to be loaded from the cache");
+        assertThrows(
+                VerificationException.class,
+                () -> verifier.verifyTextInLog(String.format(CACHE_BUILD_LOG, MODULE_NAME_2)),
+                "not expected to be loaded from the cache");
+    }
+}
diff --git a/src/test/java/org/apache/maven/buildcache/util/LogFileUtils.java b/src/test/java/org/apache/maven/buildcache/util/LogFileUtils.java
index 58f65c9..c7ac884 100644
--- a/src/test/java/org/apache/maven/buildcache/util/LogFileUtils.java
+++ b/src/test/java/org/apache/maven/buildcache/util/LogFileUtils.java
@@ -21,6 +21,7 @@ package org.apache.maven.buildcache.util;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import org.apache.maven.it.VerificationException;
 import org.apache.maven.it.Verifier;
@@ -60,4 +61,20 @@ public final class LogFileUtils {
 
         return null;
     }
+
+    /**
+     * Find lines matching all the strings given as parameter in the log file attached to a verifier
+     * @param verifier the maven verifier instance
+     * @param texts all the matching strings to find
+     * @return a list of matching strings
+     * @throws VerificationException
+     */
+    public static List<String> findLinesContainingTextsInLogs(final Verifier verifier, final String... texts)
+            throws VerificationException {
+        List<String> lines = verifier.loadFile(verifier.getBasedir(), verifier.getLogFileName(), false);
+        return lines.stream()
+                .map(s -> verifier.stripAnsi(s))
+                .filter(s -> Arrays.stream(texts).allMatch(text -> s.contains(text)))
+                .collect(Collectors.toList());
+    }
 }
diff --git a/src/test/projects/mandatory-clean/.mvn/extensions.xml b/src/test/projects/mandatory-clean/.mvn/extensions.xml
new file mode 100644
index 0000000..8df78f8
--- /dev/null
+++ b/src/test/projects/mandatory-clean/.mvn/extensions.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright 2021 the original author or authors.
+
+    Licensed 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.
+
+-->
+<extensions>
+    <extension>
+        <groupId>org.apache.maven.extensions</groupId>
+        <artifactId>maven-build-cache-extension</artifactId>
+        <version>${projectVersion}</version>
+    </extension>
+</extensions>
diff --git a/src/test/projects/mandatory-clean/.mvn/maven-build-cache-config.xml b/src/test/projects/mandatory-clean/.mvn/maven-build-cache-config.xml
new file mode 100644
index 0000000..9f7c588
--- /dev/null
+++ b/src/test/projects/mandatory-clean/.mvn/maven-build-cache-config.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<cache xmlns="http://maven.apache.org/CACHE-CONFIG/1.0.0">
+
+    <configuration>
+        <mandatoryClean>true</mandatoryClean>
+    </configuration>
+
+</cache>
diff --git a/src/test/projects/mandatory-clean/forked-module/pom.xml b/src/test/projects/mandatory-clean/forked-module/pom.xml
new file mode 100644
index 0000000..a20c2ed
--- /dev/null
+++ b/src/test/projects/mandatory-clean/forked-module/pom.xml
@@ -0,0 +1,56 @@
+<!--
+
+    Copyright 2021 the original author or authors.
+
+    Licensed 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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <parent>
+        <groupId>org.apache.maven.caching.test.simple</groupId>
+        <artifactId>parent-multi-module</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.maven.caching.test.simple</groupId>
+    <artifactId>forked-module</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>jar</packaging>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-pmd-plugin</artifactId>
+                <version>3.19.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>check</goal>
+                            <goal>pmd</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.maven.wagon</groupId>
+                        <artifactId>wagon-http</artifactId>
+                        <version>3.5.2</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/src/test/projects/mandatory-clean/forked-module/src/main/java/org/apache/maven/buildcache/ForkedExecutionClass.java b/src/test/projects/mandatory-clean/forked-module/src/main/java/org/apache/maven/buildcache/ForkedExecutionClass.java
new file mode 100644
index 0000000..920b9f9
--- /dev/null
+++ b/src/test/projects/mandatory-clean/forked-module/src/main/java/org/apache/maven/buildcache/ForkedExecutionClass.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+package org.apache.maven.buildcache;
+
+class ForkedExecutionClass
+{
+
+}
\ No newline at end of file
diff --git a/src/test/projects/mandatory-clean/non-forked-module/pom.xml b/src/test/projects/mandatory-clean/non-forked-module/pom.xml
new file mode 100644
index 0000000..a9d9917
--- /dev/null
+++ b/src/test/projects/mandatory-clean/non-forked-module/pom.xml
@@ -0,0 +1,32 @@
+<!--
+
+    Copyright 2021 the original author or authors.
+
+    Licensed 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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <parent>
+        <groupId>org.apache.maven.caching.test.simple</groupId>
+        <artifactId>parent-multi-module</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.maven.caching.test.simple</groupId>
+    <artifactId>non-forked-module</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>jar</packaging>
+
+</project>
\ No newline at end of file
diff --git a/src/test/projects/mandatory-clean/non-forked-module/src/main/java/org/apache/maven/buildcache/Test.java b/src/test/projects/mandatory-clean/non-forked-module/src/main/java/org/apache/maven/buildcache/Test.java
new file mode 100644
index 0000000..03f66a8
--- /dev/null
+++ b/src/test/projects/mandatory-clean/non-forked-module/src/main/java/org/apache/maven/buildcache/Test.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+package org.apache.maven.buildcache;
+
+class Test
+{
+
+}
\ No newline at end of file
diff --git a/src/test/projects/mandatory-clean/pom.xml b/src/test/projects/mandatory-clean/pom.xml
new file mode 100644
index 0000000..c2390cd
--- /dev/null
+++ b/src/test/projects/mandatory-clean/pom.xml
@@ -0,0 +1,37 @@
+<!--
+
+    Copyright 2021 the original author or authors.
+
+    Licensed 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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.maven.caching.test.simple</groupId>
+    <artifactId>parent-multi-module</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+
+    <modules>
+        <module>non-forked-module</module>
+        <module>forked-module</module>
+    </modules>
+
+</project>
\ No newline at end of file