From 6d9e5e76f78c7afebac56beeb33fd59b92fc8b87 Mon Sep 17 00:00:00 2001 From: wuwen Date: Sat, 14 Dec 2024 03:30:18 +0800 Subject: [PATCH] [MRELEASE-1054] Support for excluding submodules changes. (#196) * [MRELEASE-1054] Support for excluding submodules changes. * [MRELEASE-1054] Add some unit test cases. --- .../phase/AbstractMapVersionsPhase.java | 37 +++++++++--- .../phase/AbstractRewritePomsPhase.java | 33 ++++++---- .../release/phase/AbstractScmCommitPhase.java | 34 +++++++++-- .../release/phase/MapVersionsPhaseTest.java | 60 +++++++++++++++++++ .../phase/RewritePomsForReleasePhaseTest.java | 16 +++++ .../phase/ScmCommitPreparationPhaseTest.java | 46 ++++++++++++++ .../expected-pom.xml | 37 ++++++++++++ .../pom.xml | 37 ++++++++++++ .../subproject1/expected-pom.xml | 30 ++++++++++ .../subproject1/pom.xml | 30 ++++++++++ .../subproject2/expected-pom.xml | 36 +++++++++++ .../subproject2/pom.xml | 36 +++++++++++ 12 files changed, 409 insertions(+), 23 deletions(-) create mode 100644 maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/expected-pom.xml create mode 100644 maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/pom.xml create mode 100644 maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject1/expected-pom.xml create mode 100644 maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject1/pom.xml create mode 100644 maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject2/expected-pom.xml create mode 100644 maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject2/pom.xml diff --git a/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractMapVersionsPhase.java b/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractMapVersionsPhase.java index 57605bfd8..1615d1bf5 100644 --- a/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractMapVersionsPhase.java +++ b/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractMapVersionsPhase.java @@ -18,8 +18,12 @@ */ package org.apache.maven.shared.release.phase; +import java.nio.file.FileSystems; +import java.nio.file.Paths; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.project.MavenProject; @@ -97,6 +101,8 @@ public abstract class AbstractMapVersionsPhase extends AbstractReleasePhase { */ private final boolean convertToBranch; + private final Set exclusionPatterns = new HashSet<>(); + public AbstractMapVersionsPhase( ScmRepositoryConfigurator scmRepositoryConfigurator, Prompter prompter, @@ -118,6 +124,12 @@ public ReleaseResult execute( throws ReleaseExecutionException { ReleaseResult result = new ReleaseResult(); + List additionalExcludes = releaseDescriptor.getCheckModificationExcludes(); + + if (additionalExcludes != null) { + exclusionPatterns.addAll(additionalExcludes); + } + MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects); if (releaseDescriptor.isAutoVersionSubmodules() && ArtifactUtils.isSnapshot(rootProject.getVersion())) { @@ -165,17 +177,26 @@ public ReleaseResult execute( } } } else { + for (MavenProject project : reactorProjects) { String projectId = ArtifactUtils.versionlessKey(project.getGroupId(), project.getArtifactId()); - String nextVersion = resolveNextVersion(project, projectId, releaseDescriptor, releaseEnvironment); - - if (!convertToSnapshot) { - releaseDescriptor.addReleaseVersion(projectId, nextVersion); - } else if (releaseDescriptor.isBranchCreation() && convertToBranch) { - releaseDescriptor.addReleaseVersion(projectId, nextVersion); - } else { - releaseDescriptor.addDevelopmentVersion(projectId, nextVersion); + boolean isExcludedPathFound = false; + if (project.getFile() != null) { + isExcludedPathFound = exclusionPatterns.stream() + .anyMatch(exclusionPattern -> FileSystems.getDefault() + .getPathMatcher("glob:" + exclusionPattern) + .matches(Paths.get(project.getFile().getPath()))); + } + if (!isExcludedPathFound) { + String nextVersion = resolveNextVersion(project, projectId, releaseDescriptor, releaseEnvironment); + if (!convertToSnapshot) { + releaseDescriptor.addReleaseVersion(projectId, nextVersion); + } else if (releaseDescriptor.isBranchCreation() && convertToBranch) { + releaseDescriptor.addReleaseVersion(projectId, nextVersion); + } else { + releaseDescriptor.addDevelopmentVersion(projectId, nextVersion); + } } } } diff --git a/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractRewritePomsPhase.java b/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractRewritePomsPhase.java index afd4bcccd..c049cef6d 100644 --- a/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractRewritePomsPhase.java +++ b/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractRewritePomsPhase.java @@ -19,16 +19,19 @@ package org.apache.maven.shared.release.phase; import java.io.File; -import java.net.URI; +import java.nio.file.FileSystems; +import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -106,6 +109,8 @@ public abstract class AbstractRewritePomsPhase extends AbstractReleasePhase impl private long startTime = -1 * 1000; + private final Set exclusionPatterns = new HashSet<>(); + protected AbstractRewritePomsPhase( ScmRepositoryConfigurator scmRepositoryConfigurator, Map modelETLFactories, @@ -157,6 +162,12 @@ public ReleaseResult execute( throws ReleaseExecutionException, ReleaseFailureException { ReleaseResult result = new ReleaseResult(); + List additionalExcludes = releaseDescriptor.getCheckModificationExcludes(); + + if (additionalExcludes != null) { + exclusionPatterns.addAll(additionalExcludes); + } + transform(releaseDescriptor, releaseEnvironment, reactorProjects, false, result); result.setResultCode(ReleaseResult.SUCCESS); @@ -210,17 +221,19 @@ private void transform( throws ReleaseExecutionException, ReleaseFailureException { result.setStartTime((startTime >= 0) ? startTime : System.currentTimeMillis()); - URI root = ReleaseUtil.getRootProject(reactorProjects).getBasedir().toURI(); - for (MavenProject project : reactorProjects) { - URI pom = project.getFile().toURI(); - logInfo( - result, - "Transforming " + root.relativize(pom).getPath() + ' ' - + buffer().project(project.getArtifactId()) + " '" + project.getName() + "'" - + (simulate ? " with ." + getPomSuffix() + " suffix" : "") + "..."); + final String path = project.getFile().getPath(); + if (exclusionPatterns.stream().noneMatch(exclusionPattern -> FileSystems.getDefault() + .getPathMatcher("glob:" + exclusionPattern) + .matches(Paths.get(path)))) { + logDebug( + result, + "Transforming " + path + ' ' + + buffer().project(project.getArtifactId()) + " '" + project.getName() + "'" + + (simulate ? " with ." + getPomSuffix() + " suffix" : "") + "..."); - transformProject(project, releaseDescriptor, releaseEnvironment, simulate, result); + transformProject(project, releaseDescriptor, releaseEnvironment, simulate, result); + } } } diff --git a/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractScmCommitPhase.java b/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractScmCommitPhase.java index a479cbb9a..331352304 100644 --- a/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractScmCommitPhase.java +++ b/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractScmCommitPhase.java @@ -19,9 +19,13 @@ package org.apache.maven.shared.release.phase; import java.io.File; +import java.nio.file.FileSystems; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.apache.maven.project.MavenProject; import org.apache.maven.scm.ScmException; @@ -61,6 +65,8 @@ public abstract class AbstractScmCommitPhase extends AbstractReleasePhase { */ protected final String descriptorCommentGetter; + private final Set exclusionPatterns = new HashSet<>(); + protected AbstractScmCommitPhase( ScmRepositoryConfigurator scmRepositoryConfigurator, String descriptorCommentGetter) { this.scmRepositoryConfigurator = requireNonNull(scmRepositoryConfigurator); @@ -77,6 +83,12 @@ public ReleaseResult execute( validateConfiguration(releaseDescriptor); + List additionalExcludes = releaseDescriptor.getCheckModificationExcludes(); + + if (additionalExcludes != null) { + exclusionPatterns.addAll(additionalExcludes); + } + runLogic(releaseDescriptor, releaseEnvironment, reactorProjects, relResult, false); relResult.setResultCode(ReleaseResult.SUCCESS); @@ -166,9 +178,12 @@ protected void performCheckins( } } else { List pomFiles = createPomFiles(releaseDescriptor, reactorProjects); - ScmFileSet fileSet = new ScmFileSet(new File(releaseDescriptor.getWorkingDirectory()), pomFiles); - checkin(provider, repository, fileSet, releaseDescriptor, message); + if (!pomFiles.isEmpty()) { + ScmFileSet fileSet = new ScmFileSet(new File(releaseDescriptor.getWorkingDirectory()), pomFiles); + + checkin(provider, repository, fileSet, releaseDescriptor, message); + } } } @@ -288,11 +303,20 @@ protected static List createPomFiles(ReleaseDescriptor releaseDescriptor, * @param reactorProjects a {@link java.util.List} object * @return a {@link java.util.List} object */ - protected static List createPomFiles( - ReleaseDescriptor releaseDescriptor, List reactorProjects) { + protected List createPomFiles(ReleaseDescriptor releaseDescriptor, List reactorProjects) { + List pomFiles = new ArrayList<>(); for (MavenProject project : reactorProjects) { - pomFiles.addAll(createPomFiles(releaseDescriptor, project)); + + final String path = project.getFile().getPath(); + + boolean isExcludedPathFound = exclusionPatterns.stream() + .anyMatch(exclusionPattern -> FileSystems.getDefault() + .getPathMatcher("glob:" + exclusionPattern) + .matches(Paths.get(path))); + if (!isExcludedPathFound) { + pomFiles.addAll(createPomFiles(releaseDescriptor, project)); + } } return pomFiles; } diff --git a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/MapVersionsPhaseTest.java b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/MapVersionsPhaseTest.java index 36baf5df2..75f41215d 100644 --- a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/MapVersionsPhaseTest.java +++ b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/MapVersionsPhaseTest.java @@ -18,6 +18,7 @@ */ package org.apache.maven.shared.release.phase; +import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -2447,6 +2448,55 @@ public void testUpdateDevelopmentInvalidDefaultDevelopmentVersion_NonInteractive } } + @Test + public void testSimulateRelease_CheckModificationExcludes() throws Exception { + // verify + MapReleaseVersionsPhase phase = + new MapReleaseVersionsPhase(scmRepositoryConfigurator, mockPrompter, versionPolicies); + + List reactorProjects = new ArrayList<>(); + Collections.addAll( + reactorProjects, + createProject("bar", "1.11-SNAPSHOT"), + createProjectWithPomFile( + "artifactId", "1.2-SNAPSHOT", "src/test/resources/projects/scm-commit/multiple-poms/pom.xml"), + createProjectWithPomFile( + "subproject1", + "2.0", + "src/test/resources/projects/scm-commit/multiple-poms/subproject1/pom.xml")); + + ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder(); + builder.setCheckModificationExcludes(Collections.singletonList("**/subproject1/pom.xml")); + builder.setInteractive(false); + + // test + phase.simulate(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects); + + // verify + assertEquals( + "Check release versions", + "1.2", + ReleaseUtils.buildReleaseDescriptor(builder).getProjectReleaseVersion("groupId:artifactId")); + assertNull( + "Check development versions", + ReleaseUtils.buildReleaseDescriptor(builder).getProjectDevelopmentVersion("groupId:artifactId")); + + assertEquals( + "Check release versions", + "1.11", + ReleaseUtils.buildReleaseDescriptor(builder).getProjectReleaseVersion("groupId:bar")); + assertNull( + "Check development versions", + ReleaseUtils.buildReleaseDescriptor(builder).getProjectDevelopmentVersion("groupId:bar")); + + assertNull( + "Check release versions", + ReleaseUtils.buildReleaseDescriptor(builder).getProjectReleaseVersion("groupId:subproject1")); + assertNull( + "Check development versions", + ReleaseUtils.buildReleaseDescriptor(builder).getProjectDevelopmentVersion("groupId:subproject1")); + } + private static MavenProject createProject(String artifactId, String version) { Model model = new Model(); model.setGroupId("groupId"); @@ -2454,4 +2504,14 @@ private static MavenProject createProject(String artifactId, String version) { model.setVersion(version); return new MavenProject(model); } + + private static MavenProject createProjectWithPomFile(String artifactId, String version, String pathName) { + Model model = new Model(); + model.setGroupId("groupId"); + model.setArtifactId(artifactId); + model.setVersion(version); + MavenProject mavenProject = new MavenProject(model); + mavenProject.setFile(new File(pathName)); + return mavenProject; + } } diff --git a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/RewritePomsForReleasePhaseTest.java b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/RewritePomsForReleasePhaseTest.java index 71515aed7..ee71ff20e 100644 --- a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/RewritePomsForReleasePhaseTest.java +++ b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/RewritePomsForReleasePhaseTest.java @@ -21,6 +21,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Objects; @@ -454,4 +455,19 @@ public void testRewritePomWithDifferentVersionsAcrossModules() throws Exception assertTrue(comparePomFiles(reactorProjects)); } + + @Test + public void testRewritePomWithCheckModificationExcludes() throws Exception { + List reactorProjects = createReactorProjects("multimodule-with-check-modification-excludes"); + + ReleaseDescriptorBuilder builder = + createDescriptorFromProjects(reactorProjects, "multimodule-with-check-modification-excludes"); + builder.addReleaseVersion("groupId:artifactId", NEXT_VERSION); + builder.addReleaseVersion("groupId:subproject1", ALTERNATIVE_NEXT_VERSION); + builder.setCheckModificationExcludes(Collections.singletonList("**/subproject2/*")); + + phase.execute(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects); + + assertTrue(comparePomFiles(reactorProjects)); + } } diff --git a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/ScmCommitPreparationPhaseTest.java b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/ScmCommitPreparationPhaseTest.java index d4e04cf84..9c64eea8b 100644 --- a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/ScmCommitPreparationPhaseTest.java +++ b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/ScmCommitPreparationPhaseTest.java @@ -521,6 +521,52 @@ public void testSuppressCommitAfterBranch() throws Exception { verifyNoMoreInteractions(scmProviderMock); } + @Test + public void testCommitMultiModuleWithCheckModificationExcludes() throws Exception { + // prepare + ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder(); + String dir = "scm-commit/multiple-poms"; + List reactorProjects = createReactorProjects(dir, dir, null); + builder.setScmSourceUrl("scm-url"); + MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects); + builder.setWorkingDirectory(rootProject.getFile().getParentFile().getAbsolutePath()); + builder.setScmReleaseLabel("release-label"); + builder.setCheckModificationExcludes(Collections.singletonList("**/subproject2/*")); + + List poms = new ArrayList<>(); + for (Iterator i = reactorProjects.iterator(); i.hasNext(); ) { + MavenProject project = i.next(); + // This is a mock match that verifies that the project has not been submitted + if (!"subproject2".equals(project.getName())) { + poms.add(project.getFile()); + } + } + ScmFileSet fileSet = new ScmFileSet(rootProject.getFile().getParentFile(), poms); + + ScmProvider scmProviderMock = mock(ScmProvider.class); + when(scmProviderMock.checkIn( + isA(ScmRepository.class), + argThat(new IsScmFileSetEquals(fileSet)), + isNull(ScmVersion.class), + eq(PREFIX + "release-label"))) + .thenReturn(new CheckInScmResult( + "...", + Collections.singletonList( + new ScmFile(rootProject.getFile().getPath(), ScmFileStatus.CHECKED_IN)))); + ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class); + stub.setScmProvider(scmProviderMock); + + // execute + phase.execute(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects); + + // verify + verify(scmProviderMock) + .checkIn( + isA(ScmRepository.class), argThat(new IsScmFileSetEquals(fileSet)), + isNull(ScmVersion.class), eq(PREFIX + "release-label")); + verifyNoMoreInteractions(scmProviderMock); + } + private List createReactorProjects() throws Exception { String dir = "scm-commit/single-pom"; return createReactorProjects(dir, dir, null); diff --git a/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/expected-pom.xml b/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/expected-pom.xml new file mode 100644 index 000000000..e2e54a297 --- /dev/null +++ b/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/expected-pom.xml @@ -0,0 +1,37 @@ + + + + 4.0.0 + groupId + artifactId + 1.0 + pom + + + scm:svn:file://localhost/tmp/scm-repo/tags/release-label + scm:svn:file://localhost/tmp/scm-repo/tags/release-label + file://localhost/tmp/scm-repo/tags/release-label + + + + subproject1 + subproject2 + + diff --git a/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/pom.xml b/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/pom.xml new file mode 100644 index 000000000..e51608bf3 --- /dev/null +++ b/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/pom.xml @@ -0,0 +1,37 @@ + + + + 4.0.0 + groupId + artifactId + 1.0-SNAPSHOT + pom + + + scm:svn:file://localhost/tmp/scm-repo/trunk + scm:svn:file://localhost/tmp/scm-repo/trunk + file://localhost/tmp/scm-repo/trunk + + + + subproject1 + subproject2 + + diff --git a/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject1/expected-pom.xml b/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject1/expected-pom.xml new file mode 100644 index 000000000..6d39eb267 --- /dev/null +++ b/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject1/expected-pom.xml @@ -0,0 +1,30 @@ + + + + 4.0.0 + + groupId + artifactId + 1.0 + + + subproject1 + 2.0 + diff --git a/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject1/pom.xml b/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject1/pom.xml new file mode 100644 index 000000000..fd15e14f3 --- /dev/null +++ b/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject1/pom.xml @@ -0,0 +1,30 @@ + + + + 4.0.0 + + groupId + artifactId + 1.0-SNAPSHOT + + + subproject1 + 2.0-SNAPSHOT + diff --git a/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject2/expected-pom.xml b/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject2/expected-pom.xml new file mode 100644 index 000000000..559f728c0 --- /dev/null +++ b/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject2/expected-pom.xml @@ -0,0 +1,36 @@ + + + + 4.0.0 + + groupId + artifactId + 1.0-SNAPSHOT + + + + scm:svn:file://localhost/tmp/scm-repo/trunk/subproject2 + scm:svn:file://localhost/tmp/scm-repo/trunk/subproject2 + file://localhost/tmp/scm-repo/trunk/subproject2 + + + subproject2 + 2.0-SNAPSHOT + diff --git a/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject2/pom.xml b/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject2/pom.xml new file mode 100644 index 000000000..559f728c0 --- /dev/null +++ b/maven-release-manager/src/test/resources/projects/rewrite-for-release/multimodule-with-check-modification-excludes/subproject2/pom.xml @@ -0,0 +1,36 @@ + + + + 4.0.0 + + groupId + artifactId + 1.0-SNAPSHOT + + + + scm:svn:file://localhost/tmp/scm-repo/trunk/subproject2 + scm:svn:file://localhost/tmp/scm-repo/trunk/subproject2 + file://localhost/tmp/scm-repo/trunk/subproject2 + + + subproject2 + 2.0-SNAPSHOT +