From 9362da2c1390d180593b2f7cefbae03c09c64aef Mon Sep 17 00:00:00 2001 From: Andrzej Jarmoniuk Date: Fri, 14 Oct 2022 19:50:19 +0200 Subject: [PATCH] #367: Include parent projects in property resolution --- .../codehaus/mojo/versions/api/PomHelper.java | 304 +++++++++++------- .../DisplayPropertyUpdatesMojoTest.java | 88 +++++ .../mojo/versions/utils/TestUtils.java | 33 ++ .../issue-367/child/pom.xml | 20 ++ .../issue-367/pom.xml | 11 + 5 files changed, 333 insertions(+), 123 deletions(-) create mode 100644 src/test/java/org/codehaus/mojo/versions/DisplayPropertyUpdatesMojoTest.java create mode 100644 src/test/resources/org/codehaus/mojo/display-property-updates/issue-367/child/pom.xml create mode 100644 src/test/resources/org/codehaus/mojo/display-property-updates/issue-367/pom.xml diff --git a/src/main/java/org/codehaus/mojo/versions/api/PomHelper.java b/src/main/java/org/codehaus/mojo/versions/api/PomHelper.java index 8c66929c67..eeefac1d11 100644 --- a/src/main/java/org/codehaus/mojo/versions/api/PomHelper.java +++ b/src/main/java/org/codehaus/mojo/versions/api/PomHelper.java @@ -22,11 +22,13 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.XMLEvent; +import java.io.BufferedReader; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -90,7 +92,7 @@ public class PomHelper * @throws IOException if the file is not found or if the file does not parse. */ public static Model getRawModel( MavenProject project ) - throws IOException + throws IOException { return getRawModel( project.getFile() ); } @@ -103,15 +105,12 @@ public static Model getRawModel( MavenProject project ) * @throws IOException if the file is not found or if the file does not parse. */ public static Model getRawModel( File moduleProjectFile ) - throws IOException + throws IOException { - try ( FileInputStream input = new FileInputStream( moduleProjectFile ) ) + try ( Reader reader = new BufferedReader( new InputStreamReader( Files.newInputStream( moduleProjectFile + .toPath() ) ) ) ) { - return new MavenXpp3Reader().read( input ); - } - catch ( XmlPullParserException e ) - { - throw new IOException( e.getMessage(), e ); + return getRawModel( reader ); } } @@ -123,11 +122,27 @@ public static Model getRawModel( File moduleProjectFile ) * @throws IOException if the file is not found or if the file does not parse. */ public static Model getRawModel( ModifiedPomXMLEventReader modifiedPomXMLEventReader ) - throws IOException + throws IOException + { + try ( Reader reader = new StringReader( modifiedPomXMLEventReader.asStringBuilder().toString() ) ) + { + return getRawModel( reader ); + } + } + + /** + * Gets the current raw model before any interpolation what-so-ever. + * + * @param reader The {@link Reader} to get the raw model for. + * @return The raw model. + * @throws IOException if the file is not found or if the file does not parse. + */ + public static Model getRawModel( Reader reader ) + throws IOException { - try ( StringReader stringReader = new StringReader( modifiedPomXMLEventReader.asStringBuilder().toString() ) ) + try { - return new MavenXpp3Reader().read( stringReader ); + return new MavenXpp3Reader().read( reader ); } catch ( XmlPullParserException e ) { @@ -147,7 +162,7 @@ public static Model getRawModel( ModifiedPomXMLEventReader modifiedPomXMLEventRe */ public static boolean setPropertyVersion( final ModifiedPomXMLEventReader pom, final String profileId, final String property, final String value ) - throws XMLStreamException + throws XMLStreamException { Stack stack = new Stack<>(); String path = ""; @@ -231,7 +246,7 @@ else if ( matchScopeRegex.matcher( path ).matches() ) * @throws XMLStreamException if somethinh went wrong. */ public static boolean setProjectVersion( final ModifiedPomXMLEventReader pom, final String value ) - throws XMLStreamException + throws XMLStreamException { return setElementValue( pom, "/project", "version", value, false ); } @@ -241,15 +256,15 @@ public static boolean setProjectVersion( final ModifiedPomXMLEventReader pom, fi * Will only consider the first found occurrence of the parent element. * If the element is not found in the parent element, the method will create the element. * - * @param pom pom to modify - * @param parentPath path of the parent element - * @param elementName name of the element to set or create - * @param value the new value of the element - * @return {@code true} if the element was created or replaced + * @param pom pom to modify + * @param parentPath path of the parent element + * @param elementName name of the element to set or create + * @param value the new value of the element + * @return {@code true} if the element was created or replaced * @throws XMLStreamException if something went wrong */ public static boolean setElementValue( ModifiedPomXMLEventReader pom, String parentPath, - String elementName, String value ) + String elementName, String value ) throws XMLStreamException { pom.rewind(); @@ -262,13 +277,13 @@ public static boolean setElementValue( ModifiedPomXMLEventReader pom, String par * If the element is not found in the parent element, the method will create the element * if {@code shouldCreate} is {@code true}. * - * @param pom pom to modify - * @param parentPath path of the parent element - * @param elementName name of the element to set or create - * @param value the new value of the element - * @param shouldCreate should the element be created if it's not found in the first encountered parent element - * matching the parentPath - * @return {@code true} if the element was created or replaced + * @param pom pom to modify + * @param parentPath path of the parent element + * @param elementName name of the element to set or create + * @param value the new value of the element + * @param shouldCreate should the element be created if it's not found in the first encountered parent element + * matching the parentPath + * @return {@code true} if the element was created or replaced * @throws XMLStreamException if something went wrong */ public static boolean setElementValue( ModifiedPomXMLEventReader pom, String parentPath, @@ -308,7 +323,7 @@ boolean process( String currentPath ) throws XMLStreamException } else if ( currentPath.equals( superParentPath ) && currentElementName.equals( parentName ) ) { - pom.mark( PARENT_BEGIN ); + pom.mark( PARENT_BEGIN ); } // process child element replacementMade = process( currentPath + "/" + currentElementName ); @@ -394,7 +409,7 @@ private void replaceValueInParent() * @throws XMLStreamException if something went wrong. */ public static String getProjectVersion( final ModifiedPomXMLEventReader pom ) - throws XMLStreamException + throws XMLStreamException { Stack stack = new Stack<>(); String path = ""; @@ -442,7 +457,7 @@ public static String getProjectVersion( final ModifiedPomXMLEventReader pom ) * @throws XMLStreamException if somethinh went wrong. */ public static boolean setProjectParentVersion( final ModifiedPomXMLEventReader pom, final String value ) - throws XMLStreamException + throws XMLStreamException { Stack stack = new Stack<>(); String path = ""; @@ -493,7 +508,7 @@ public static boolean setProjectParentVersion( final ModifiedPomXMLEventReader p * @throws XMLStreamException if something went wrong. */ public static Artifact getProjectParent( final ModifiedPomXMLEventReader pom, VersionsHelper helper ) - throws XMLStreamException + throws XMLStreamException { Stack stack = new Stack<>(); String path = ""; @@ -542,7 +557,7 @@ else if ( "version".equals( elementName ) ) return null; } return helper.createDependencyArtifact( groupId, artifactId, version, "pom", - null, null ); + null, null ); } /** @@ -561,15 +576,15 @@ else if ( "version".equals( elementName ) ) public static boolean setDependencyVersion( final ModifiedPomXMLEventReader pom, final String groupId, final String artifactId, final String oldVersion, final String newVersion, final Model model ) - throws XMLStreamException + throws XMLStreamException { Stack stack = new Stack<>(); String path = ""; Set implicitPaths = - new HashSet<>( Arrays.asList( "/project/parent/groupId", "/project/parent/artifactId", - "/project/parent/version", "/project/groupId", - "/project/artifactId", "/project/version" ) ); + new HashSet<>( Arrays.asList( "/project/parent/groupId", "/project/parent/artifactId", + "/project/parent/version", "/project/groupId", + "/project/artifactId", "/project/version" ) ); Map implicitProperties = new HashMap<>(); for ( Map.Entry entry : model.getProperties().entrySet() ) @@ -632,15 +647,15 @@ public static boolean setDependencyVersion( final ModifiedPomXMLEventReader pom, boolean haveOldVersion = false; final Pattern matchScopeRegex = Pattern.compile( - "/project" + "(/profiles/profile)?" - + "((/dependencyManagement)|(/build(/pluginManagement)?/plugins/plugin))?" - + "/dependencies/dependency" ); + "/project" + "(/profiles/profile)?" + + "((/dependencyManagement)|(/build(/pluginManagement)?/plugins/plugin))?" + + "/dependencies/dependency" ); final Pattern matchTargetRegex = Pattern.compile( - "/project" + "(/profiles/profile)?" - + "((/dependencyManagement)|(/build(/pluginManagement)?/plugins/plugin))?" - + "/dependencies/dependency" - + "((/groupId)|(/artifactId)|(/version))" ); + "/project" + "(/profiles/profile)?" + + "((/dependencyManagement)|(/build(/pluginManagement)?/plugins/plugin))?" + + "/dependencies/dependency" + + "((/groupId)|(/artifactId)|(/version))" ); pom.rewind(); @@ -675,7 +690,7 @@ else if ( inMatchScope && matchTargetRegex.matcher( path ).matches() ) else if ( "artifactId".equals( elementName ) ) { haveArtifactId = - artifactId.equals( evaluate( pom.getElementText().trim(), implicitProperties ) ); + artifactId.equals( evaluate( pom.getElementText().trim(), implicitProperties ) ); path = stack.pop(); } else if ( "version".equals( elementName ) ) @@ -687,7 +702,7 @@ else if ( "version".equals( elementName ) ) if ( event.isEndElement() ) { if ( matchTargetRegex.matcher( path ).matches() - && "version".equals( event.asEndElement().getName().getLocalPart() ) ) + && "version".equals( event.asEndElement().getName().getLocalPart() ) ) { pom.mark( 1 ); String compressedPomVersion = StringUtils.deleteWhitespace( pom.getBetween( 0, 1 ).trim() ); @@ -706,7 +721,7 @@ else if ( "version".equals( elementName ) ) else if ( matchScopeRegex.matcher( path ).matches() ) { if ( inMatchScope && pom.hasMark( 0 ) && pom.hasMark( 1 ) && haveGroupId && haveArtifactId - && haveOldVersion ) + && haveOldVersion ) { pom.replaceBetween( 0, 1, newVersion ); madeReplacement = true; @@ -785,7 +800,7 @@ public static String evaluate( String expr, Map properties ) if ( exprStartDelimiter > 0 ) { value = value.substring( 0, exprStartDelimiter ) - + evaluate( value.substring( exprStartDelimiter ), properties ); + + evaluate( value.substring( exprStartDelimiter ), properties ); } else { @@ -826,7 +841,7 @@ private static String stripTokens( String expr ) * @throws InvalidVersionSpecificationException if the versions can't be parsed to a range */ public static boolean isVersionOverlap( String leftVersionOrRange, String rightVersionOrRange ) - throws InvalidVersionSpecificationException + throws InvalidVersionSpecificationException { VersionRange pomVersionRange = createVersionRange( leftVersionOrRange ); if ( !pomVersionRange.hasRestrictions() ) @@ -845,7 +860,7 @@ public static boolean isVersionOverlap( String leftVersionOrRange, String rightV } private static VersionRange createVersionRange( String versionOrRange ) - throws InvalidVersionSpecificationException + throws InvalidVersionSpecificationException { VersionRange versionRange = VersionRange.createFromVersionSpec( versionOrRange ); if ( versionRange.getRecommendedVersion() != null ) @@ -868,7 +883,7 @@ private static VersionRange createVersionRange( String versionOrRange ) */ public static boolean setPluginVersion( final ModifiedPomXMLEventReader pom, final String groupId, final String artifactId, final String oldVersion, final String newVersion ) - throws XMLStreamException + throws XMLStreamException { Stack stack = new Stack<>(); String path = ""; @@ -882,11 +897,11 @@ public static boolean setPluginVersion( final ModifiedPomXMLEventReader pom, fin boolean haveOldVersion = false; matchScopeRegex = Pattern.compile( "/project" + "(/profiles/profile)?" - + "((/build(/pluginManagement)?)|(/reporting))/plugins/plugin" ); + + "((/build(/pluginManagement)?)|(/reporting))/plugins/plugin" ); matchTargetRegex = Pattern.compile( "/project" + "(/profiles/profile)?" - + "((/build(/pluginManagement)?)|(/reporting))/plugins/plugin" - + "((/groupId)|(/artifactId)|(/version))" ); + + "((/build(/pluginManagement)?)|(/reporting))/plugins/plugin" + + "((/groupId)|(/artifactId)|(/version))" ); pom.rewind(); @@ -915,7 +930,7 @@ else if ( inMatchScope && matchTargetRegex.matcher( path ).matches() ) { if ( "groupId".equals( elementName ) ) { - haveGroupId = pom.getElementText().trim().equals( groupId ); + haveGroupId = pom.getElementText().trim().equals( groupId ); path = stack.pop(); } else if ( "artifactId".equals( elementName ) ) @@ -932,7 +947,7 @@ else if ( "version".equals( elementName ) ) if ( event.isEndElement() ) { if ( matchTargetRegex.matcher( path ).matches() - && "version".equals( event.asEndElement().getName().getLocalPart() ) ) + && "version".equals( event.asEndElement().getName().getLocalPart() ) ) { pom.mark( 1 ); @@ -949,7 +964,7 @@ else if ( "version".equals( elementName ) ) else if ( matchScopeRegex.matcher( path ).matches() ) { if ( inMatchScope && pom.hasMark( 0 ) && pom.hasMark( 1 ) && ( haveGroupId || !needGroupId ) - && haveArtifactId && haveOldVersion ) + && haveArtifactId && haveOldVersion ) { pom.replaceBetween( 0, 1, newVersion ); madeReplacement = true; @@ -967,6 +982,37 @@ else if ( matchScopeRegex.matcher( path ).matches() ) return madeReplacement; } + /** + * Traverses the project tree upwards, adding the raw models of every project it encounters to the map + * + * @param project maven project of the child for which the models need to be gathered + * @return gathered map of raw models per project + */ + private static Map getRawModelWithParents( MavenProject project ) throws IOException + { + // constructs a tree sorted from children to parents + Map models = new TreeMap<>( ( p1, p2 ) -> + { + for ( MavenProject p = p1; p != null; p = p.getParent() ) + { + if ( p == p2 ) // meaning p2 is an ancestor to p1 or p1 == p2 + { + return p == p1 + ? 0 + : -1; // p1 is the child + } + } + return 1; + } ); + for ( MavenProject p = project; p != null; p = p.getParent() ) + { + models.put( p, p.getFile() != null + ? getRawModel( p ) + : p.getOriginalModel() ); + } + return models; + } + /** * Examines the project to find any properties which are associated with versions of artifacts in the project. * @@ -978,11 +1024,12 @@ else if ( matchScopeRegex.matcher( path ).matches() ) * @since 1.0-alpha-3 */ public static PropertyVersionsBuilder[] getPropertyVersionsBuilders( VersionsHelper helper, MavenProject project ) - throws ExpressionEvaluationException, IOException + throws ExpressionEvaluationException, IOException { ExpressionEvaluator expressionEvaluator = helper.getExpressionEvaluator( project ); - Model projectModel = getRawModel( project ); - Map result = new TreeMap<>(); + Map reactorModels = getRawModelWithParents( project ); + + Map propertiesMap = new TreeMap<>(); Set activeProfiles = new TreeSet<>(); for ( Profile profile : project.getActiveProfiles() ) @@ -991,58 +1038,72 @@ public static PropertyVersionsBuilder[] getPropertyVersionsBuilders( VersionsHel } // add any properties from profiles first (as they override properties from the project - for ( Profile profile : projectModel.getProfiles() ) + for ( Iterator it = reactorModels.values().stream() + .flatMap( model -> model.getProfiles().stream() ) + .filter( profile -> activeProfiles.contains( profile.getId() ) ) + .iterator(); it.hasNext(); ) { - if ( !activeProfiles.contains( profile.getId() ) ) - { - continue; - } - addProperties( helper, result, profile.getId(), profile.getProperties() ); - if ( profile.getDependencyManagement() != null ) - { - addDependencyAssocations( helper, expressionEvaluator, result, - profile.getDependencyManagement().getDependencies(), false ); - } - addDependencyAssocations( helper, expressionEvaluator, result, profile.getDependencies(), false ); - if ( profile.getBuild() != null ) + Profile profile = it.next(); + try { - if ( profile.getBuild().getPluginManagement() != null ) + addProperties( helper, propertiesMap, profile.getId(), profile.getProperties() ); + if ( profile.getDependencyManagement() != null ) { - addPluginAssociations( helper, expressionEvaluator, result, - profile.getBuild().getPluginManagement().getPlugins() ); + addDependencyAssocations( helper, expressionEvaluator, propertiesMap, + profile.getDependencyManagement().getDependencies(), false ); + } + addDependencyAssocations( helper, expressionEvaluator, propertiesMap, + profile.getDependencies(), + false ); + if ( profile.getBuild() != null ) + { + if ( profile.getBuild().getPluginManagement() != null ) + { + addPluginAssociations( helper, expressionEvaluator, propertiesMap, + profile.getBuild().getPluginManagement().getPlugins() ); + } + addPluginAssociations( helper, expressionEvaluator, propertiesMap, + profile.getBuild().getPlugins() ); + } + if ( profile.getReporting() != null ) + { + addReportPluginAssociations( helper, expressionEvaluator, propertiesMap, + profile.getReporting().getPlugins() ); } - addPluginAssociations( helper, expressionEvaluator, result, profile.getBuild().getPlugins() ); } - if ( profile.getReporting() != null ) + catch ( ExpressionEvaluationException e ) { - addReportPluginAssociations( helper, expressionEvaluator, result, profile.getReporting().getPlugins() ); + throw new RuntimeException( e ); } } // second, we add all the properties in the pom - addProperties( helper, result, null, projectModel.getProperties() ); - Model model = projectModel; - MavenProject currentPrj = project; - while ( currentPrj != null ) + reactorModels.values().forEach( model -> addProperties( helper, propertiesMap, null, model.getProperties() ) ); + + + for ( MavenProject currentPrj = project; currentPrj != null; currentPrj = currentPrj.getParent() ) { + Model model = reactorModels.get( currentPrj ); + if ( model.getDependencyManagement() != null ) { - addDependencyAssocations( helper, expressionEvaluator, result, - model.getDependencyManagement().getDependencies(), false ); + addDependencyAssocations( helper, expressionEvaluator, propertiesMap, + model.getDependencyManagement().getDependencies(), false ); } - addDependencyAssocations( helper, expressionEvaluator, result, model.getDependencies(), false ); + addDependencyAssocations( helper, expressionEvaluator, propertiesMap, model.getDependencies(), false ); if ( model.getBuild() != null ) { if ( model.getBuild().getPluginManagement() != null ) { - addPluginAssociations( helper, expressionEvaluator, result, - model.getBuild().getPluginManagement().getPlugins() ); + addPluginAssociations( helper, expressionEvaluator, propertiesMap, + model.getBuild().getPluginManagement().getPlugins() ); } - addPluginAssociations( helper, expressionEvaluator, result, model.getBuild().getPlugins() ); + addPluginAssociations( helper, expressionEvaluator, propertiesMap, model.getBuild().getPlugins() ); } if ( model.getReporting() != null ) { - addReportPluginAssociations( helper, expressionEvaluator, result, model.getReporting().getPlugins() ); + addReportPluginAssociations( helper, expressionEvaluator, propertiesMap, + model.getReporting().getPlugins() ); } // third, we add any associations from the active profiles @@ -1054,36 +1115,33 @@ public static PropertyVersionsBuilder[] getPropertyVersionsBuilders( VersionsHel } if ( profile.getDependencyManagement() != null ) { - addDependencyAssocations( helper, expressionEvaluator, result, - profile.getDependencyManagement().getDependencies(), false ); + addDependencyAssocations( helper, expressionEvaluator, propertiesMap, + profile.getDependencyManagement().getDependencies(), false ); } - addDependencyAssocations( helper, expressionEvaluator, result, profile.getDependencies(), false ); + addDependencyAssocations( helper, expressionEvaluator, propertiesMap, profile.getDependencies(), + false ); if ( profile.getBuild() != null ) { if ( profile.getBuild().getPluginManagement() != null ) { - addPluginAssociations( helper, expressionEvaluator, result, - profile.getBuild().getPluginManagement().getPlugins() ); + addPluginAssociations( helper, expressionEvaluator, propertiesMap, + profile.getBuild().getPluginManagement().getPlugins() ); } - addPluginAssociations( helper, expressionEvaluator, result, profile.getBuild().getPlugins() ); + addPluginAssociations( helper, expressionEvaluator, propertiesMap, + profile.getBuild().getPlugins() ); } if ( profile.getReporting() != null ) { - addReportPluginAssociations( helper, expressionEvaluator, result, - profile.getReporting().getPlugins() ); + addReportPluginAssociations( helper, expressionEvaluator, propertiesMap, + profile.getReporting().getPlugins() ); } } - currentPrj = currentPrj.getParent(); - if ( currentPrj != null ) - { - model = currentPrj.getOriginalModel(); - } } // finally, remove any properties without associations - purgeProperties( result ); + purgeProperties( propertiesMap ); - return result.values().toArray( new PropertyVersionsBuilder[0] ); + return propertiesMap.values().toArray( new PropertyVersionsBuilder[0] ); } /** @@ -1099,7 +1157,7 @@ public static PropertyVersionsBuilder[] getPropertyVersionsBuilders( VersionsHel */ private static void addPluginAssociations( VersionsHelper helper, ExpressionEvaluator expressionEvaluator, Map result, List plugins ) - throws ExpressionEvaluationException + throws ExpressionEvaluationException { if ( plugins == null ) { @@ -1140,7 +1198,7 @@ private static void addPluginAssociations( VersionsHelper helper, ExpressionEval // might as well capture the current value String evaluatedVersion = (String) expressionEvaluator.evaluate( plugin.getVersion() ); property.addAssociation( helper.createPluginArtifact( groupId, artifactId, evaluatedVersion ), - true ); + true ); if ( !propertyRef.equals( version ) ) { addBounds( property, version, propertyRef ); @@ -1155,7 +1213,7 @@ private static void addPluginAssociations( VersionsHelper helper, ExpressionEval private static void addReportPluginAssociations( VersionsHelper helper, ExpressionEvaluator expressionEvaluator, Map result, List reportPlugins ) - throws ExpressionEvaluationException + throws ExpressionEvaluationException { if ( reportPlugins == null ) { @@ -1196,7 +1254,7 @@ private static void addReportPluginAssociations( VersionsHelper helper, Expressi // might as well capture the current value String versionEvaluated = (String) expressionEvaluator.evaluate( plugin.getVersion() ); property.addAssociation( helper.createPluginArtifact( groupId, artifactId, versionEvaluated ), - true ); + true ); if ( !propertyRef.equals( version ) ) { addBounds( property, version, propertyRef ); @@ -1210,7 +1268,7 @@ private static void addReportPluginAssociations( VersionsHelper helper, Expressi private static void addDependencyAssocations( VersionsHelper helper, ExpressionEvaluator expressionEvaluator, Map result, List dependencies, boolean usePluginRepositories ) - throws ExpressionEvaluationException + throws ExpressionEvaluationException { if ( dependencies == null ) { @@ -1251,11 +1309,11 @@ private static void addDependencyAssocations( VersionsHelper helper, ExpressionE // might as well capture the current value String versionEvaluated = (String) expressionEvaluator.evaluate( dependency.getVersion() ); property.addAssociation( helper.createDependencyArtifact( groupId, artifactId, versionEvaluated, - dependency.getType(), - dependency.getClassifier(), - dependency.getScope(), - dependency.isOptional() ), - usePluginRepositories ); + dependency.getType(), + dependency.getClassifier(), + dependency.getScope(), + dependency.isOptional() ), + usePluginRepositories ); if ( !propertyRef.equals( version ) ) { addBounds( property, version, propertyRef ); @@ -1299,7 +1357,7 @@ private static void addProperties( VersionsHelper helper, Map getReactorModels( MavenProject project, Log logger ) - throws IOException + throws IOException { Map result = new LinkedHashMap<>(); final Model model = getRawModel( project ); @@ -1552,7 +1610,7 @@ public static Map getReactorModels( MavenProject project, Log log * @throws IOException if things go wrong. */ private static Map getReactorModels( String path, Model model, MavenProject project, Log logger ) - throws IOException + throws IOException { if ( path.length() > 0 && !path.endsWith( "/" ) ) { @@ -1620,7 +1678,7 @@ public static Map getChildModels( Map reactor, Str final Model model = entry.getValue(); final Parent parent = model.getParent(); if ( parent != null && groupId.equals( parent.getGroupId() ) - && artifactId.equals( parent.getArtifactId() ) ) + && artifactId.equals( parent.getArtifactId() ) ) { result.put( path, model ); } @@ -1689,7 +1747,7 @@ public static int getReactorParentCount( Map reactor, Model model * @throws java.io.IOException when things go wrong. */ public static StringBuilder readXmlFile( File outFile ) - throws IOException + throws IOException { try ( Reader reader = ReaderFactory.newXmlReader( outFile ) ) { @@ -1718,7 +1776,7 @@ public static String getGAV( Model model ) * @since 2.4 */ public static List readImportedPOMsFromDependencyManagementSection( ModifiedPomXMLEventReader pom ) - throws XMLStreamException + throws XMLStreamException { List importedPOMs = new ArrayList<>(); Stack stack = new Stack<>(); @@ -1729,8 +1787,8 @@ public static List readImportedPOMsFromDependencyManagementSection( String typeElement = "type"; String scopeElement = "scope"; Set recognizedElements = - new HashSet<>( Arrays.asList( groupIdElement, artifactIdElement, versionElement, typeElement, - scopeElement ) ); + new HashSet<>( Arrays.asList( groupIdElement, artifactIdElement, versionElement, typeElement, + scopeElement ) ); Map depData = new HashMap<>(); pom.rewind(); diff --git a/src/test/java/org/codehaus/mojo/versions/DisplayPropertyUpdatesMojoTest.java b/src/test/java/org/codehaus/mojo/versions/DisplayPropertyUpdatesMojoTest.java new file mode 100644 index 0000000000..be01de3bdf --- /dev/null +++ b/src/test/java/org/codehaus/mojo/versions/DisplayPropertyUpdatesMojoTest.java @@ -0,0 +1,88 @@ +package org.codehaus.mojo.versions; +/* + * 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. + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; + +import org.apache.maven.plugin.testing.AbstractMojoTestCase; +import org.apache.maven.plugin.testing.MojoRule; +import org.codehaus.mojo.versions.utils.MockUtils; +import org.codehaus.mojo.versions.utils.TestUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import static org.apache.commons.codec.CharEncoding.UTF_8; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.matchesPattern; + +/** + * Unit tests for {@link DisplayPropertyUpdatesMojo} + */ +public class DisplayPropertyUpdatesMojoTest extends AbstractMojoTestCase +{ + @Rule + public MojoRule mojoRule = new MojoRule( this ); + + private Path tempDir; + + @Before + public void setUp() throws Exception + { + super.setUp(); + tempDir = TestUtils.createTempDir( "display-property-updates" ); + } + + @After + public void tearDown() throws Exception + { + try + { + TestUtils.tearDownTempDir( tempDir ); + } + finally + { + super.tearDown(); + } + } + + @Test + public void testPropertiesFromParent() throws Exception + { + Path tempFile = Files.createTempFile( tempDir, "output", "" ); + + TestUtils.copyDir( Paths.get( "src/test/resources/org/codehaus/mojo/display-property-updates/issue-367" ), + tempDir ); + DisplayPropertyUpdatesMojo mojo = + (DisplayPropertyUpdatesMojo) mojoRule.lookupConfiguredMojo( tempDir.resolve( "child" ).toFile(), + "display-property-updates" ); + mojo.outputEncoding = UTF_8; + mojo.outputFile = tempFile.toFile(); + mojo.setPluginContext( new HashMap<>() ); + mojo.artifactMetadataSource = MockUtils.mockArtifactMetadataSource(); + mojo.execute(); + + assertThat( String.join( "", Files.readAllLines( tempFile ) ), + matchesPattern( ".*\\$\\{ver} \\.* 1\\.0\\.0 -> 2\\.0\\.0.*" ) ); + } +} diff --git a/src/test/java/org/codehaus/mojo/versions/utils/TestUtils.java b/src/test/java/org/codehaus/mojo/versions/utils/TestUtils.java index 6e45c91b97..950a9d184d 100644 --- a/src/test/java/org/codehaus/mojo/versions/utils/TestUtils.java +++ b/src/test/java/org/codehaus/mojo/versions/utils/TestUtils.java @@ -26,6 +26,7 @@ import java.nio.file.attribute.BasicFileAttributes; import static java.nio.file.FileVisitResult.CONTINUE; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static org.apache.commons.text.CaseUtils.toCamelCase; /** @@ -35,6 +36,7 @@ public class TestUtils { /** * Creates a temporary directory with the given name + * * @param name name of the directory to create * @return {@linkplain Path} object pointing to the directory * @throws IOException should the I/O operation fail @@ -46,6 +48,7 @@ public static Path createTempDir( String name ) throws IOException /** * Deletes the given directory together with all its contents + * * @param dir directory to delete * @throws IOException should an I/O operation fail */ @@ -71,4 +74,34 @@ public FileVisitResult postVisitDirectory( Path dir, IOException exc ) throws IO } ); } } + + /** + * Copies the {@code src} directory to {@code dst} recursively, + * creating the missing directories if necessary + * + * @param src source directory path + * @param dst destination directory path + * @throws IOException should an I/O error occur + */ + public static void copyDir( Path src, Path dst ) throws IOException + { + Files.walkFileTree( src, new SimpleFileVisitor() + { + @Override + public FileVisitResult preVisitDirectory( Path dir, BasicFileAttributes attrs ) + throws IOException + { + Files.createDirectories( dst.resolve( src.relativize( dir ) ) ); + return CONTINUE; + } + + @Override + public FileVisitResult visitFile( Path file, BasicFileAttributes attrs ) + throws IOException + { + Files.copy( file, dst.resolve( src.relativize( file ) ), REPLACE_EXISTING ); + return CONTINUE; + } + } ); + } } diff --git a/src/test/resources/org/codehaus/mojo/display-property-updates/issue-367/child/pom.xml b/src/test/resources/org/codehaus/mojo/display-property-updates/issue-367/child/pom.xml new file mode 100644 index 0000000000..270daa5a5d --- /dev/null +++ b/src/test/resources/org/codehaus/mojo/display-property-updates/issue-367/child/pom.xml @@ -0,0 +1,20 @@ + + 4.0.0 + + default-group + parent + 1.0.0 + + child + + + + + default-group + artifactA + ${ver} + + + + + diff --git a/src/test/resources/org/codehaus/mojo/display-property-updates/issue-367/pom.xml b/src/test/resources/org/codehaus/mojo/display-property-updates/issue-367/pom.xml new file mode 100644 index 0000000000..3a342f4087 --- /dev/null +++ b/src/test/resources/org/codehaus/mojo/display-property-updates/issue-367/pom.xml @@ -0,0 +1,11 @@ + + 4.0.0 + default-group + parent + 1.0.0 + pom + + + 1.0.0 + +