001package org.apache.maven.plugins.enforcer; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.IOException; 023import java.util.ArrayList; 024import java.util.Arrays; 025import java.util.Collection; 026import java.util.HashMap; 027import java.util.HashSet; 028import java.util.List; 029import java.util.Map; 030import java.util.Set; 031 032import org.apache.maven.BuildFailureException; 033import org.apache.maven.artifact.Artifact; 034import org.apache.maven.artifact.factory.ArtifactFactory; 035import org.apache.maven.artifact.repository.ArtifactRepository; 036import org.apache.maven.artifact.resolver.ArtifactNotFoundException; 037import org.apache.maven.artifact.resolver.ArtifactResolutionException; 038import org.apache.maven.artifact.resolver.ArtifactResolver; 039import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; 040import org.apache.maven.artifact.versioning.VersionRange; 041import org.apache.maven.enforcer.rule.api.EnforcerRuleException; 042import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper; 043import org.apache.maven.execution.MavenSession; 044import org.apache.maven.lifecycle.DefaultLifecycles; 045import org.apache.maven.lifecycle.Lifecycle; 046import org.apache.maven.lifecycle.LifecycleExecutionException; 047import org.apache.maven.lifecycle.mapping.LifecycleMapping; 048import org.apache.maven.model.BuildBase; 049import org.apache.maven.model.Model; 050import org.apache.maven.model.Plugin; 051import org.apache.maven.model.Profile; 052import org.apache.maven.model.ReportPlugin; 053import org.apache.maven.plugin.InvalidPluginException; 054import org.apache.maven.plugin.MojoExecutionException; 055import org.apache.maven.plugin.PluginManager; 056import org.apache.maven.plugin.PluginManagerException; 057import org.apache.maven.plugin.PluginNotFoundException; 058import org.apache.maven.plugin.descriptor.PluginDescriptor; 059import org.apache.maven.plugin.logging.Log; 060import org.apache.maven.plugin.version.PluginVersionNotFoundException; 061import org.apache.maven.plugin.version.PluginVersionResolutionException; 062import org.apache.maven.plugins.enforcer.utils.EnforcerRuleUtils; 063import org.apache.maven.plugins.enforcer.utils.PluginWrapper; 064import org.apache.maven.project.MavenProject; 065import org.apache.maven.rtinfo.RuntimeInformation; 066import org.apache.maven.settings.Settings; 067import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; 068import org.codehaus.plexus.component.repository.exception.ComponentLookupException; 069import org.codehaus.plexus.util.StringUtils; 070import org.codehaus.plexus.util.xml.pull.XmlPullParserException; 071 072/** 073 * This rule will enforce that all plugins specified in the poms have a version declared. 074 * 075 * @author <a href="mailto:brianf@apache.org">Brian Fox</a> 076 */ 077public class RequirePluginVersions 078 extends AbstractNonCacheableEnforcerRule 079{ 080 081 private EnforcerRuleHelper helper; 082 083 /** 084 * Don't allow the LATEST identifier. 085 * 086 * @see {@link #setBanLatest(boolean)} 087 * @see {@link #isBanLatest()} 088 */ 089 private boolean banLatest = true; 090 091 /** 092 * Don't allow the RELEASE identifier. 093 * 094 * @see {@link #setBanRelease(boolean)} 095 * @see {@link #isBanRelease()} 096 */ 097 private boolean banRelease = true; 098 099 /** 100 * Don't allow snapshot plugins. 101 * 102 * @see {@link #setBanSnapshots(boolean)} 103 * @see {@link #isBanSnapshots()} 104 */ 105 private boolean banSnapshots = true; 106 107 /** 108 * Don't allow timestamp snapshot plugins. 109 * 110 * @see {@link #setBanTimestamps(boolean)} 111 * @see {@link #isBanTimestamps()} 112 */ 113 private boolean banTimestamps = true; 114 115 /** 116 * @since 3.0.0 117 */ 118 private boolean banMavenDefaults = true; 119 120 /** 121 * The comma separated list of phases that should be used to find lifecycle plugin bindings. The default value is 122 * "clean,deploy,site". 123 * 124 * @see {@link #setPhases(String)} 125 * @see {@link #getPhases()} 126 */ 127 private String phases = "clean,deploy,site"; 128 129 /** 130 * Additional plugins to enforce have versions. These are plugins that may not be in the poms but are used anyway, 131 * like help, eclipse etc. <br> 132 * The plugins should be specified in the form: <code>group:artifactId</code>. 133 * 134 * @see {@link #setAdditionalPlugins(List)} 135 * @see {@link #getAdditionalPlugins()} 136 */ 137 private List<String> additionalPlugins; 138 139 /** 140 * Plugins to skip for version enforcement. The plugins should be specified in the form: 141 * <code>group:artifactId</code>. NOTE: This is deprecated, use unCheckedPluginList instead. 142 * 143 * @see {@link #setUnCheckedPlugins(List)} 144 * @see {@link #getUnCheckedPlugins()} 145 */ 146 private List<String> unCheckedPlugins; 147 148 /** 149 * Same as unCheckedPlugins but as a comma list to better support properties. Sample form: 150 * <code>group:artifactId,group2:artifactId2</code> 151 * 152 * @since 1.0-beta-1 153 * @see {@link #setUnCheckedPlugins(List)} 154 * @see {@link #getUnCheckedPlugins()} 155 */ 156 private String unCheckedPluginList; 157 158 /** The plugin manager. */ 159 private PluginManager pluginManager; 160 161 /** The phase to lifecycle map. */ 162 private Map<String, Lifecycle> phaseToLifecycleMap; 163 164 /** The lifecycles. */ 165 private Collection<Lifecycle> lifecycles; 166 167 /** The factory. */ 168 private ArtifactFactory factory; 169 170 /** The resolver. */ 171 private ArtifactResolver resolver; 172 173 /** The local. */ 174 private ArtifactRepository local; 175 176 /** The log. */ 177 private Log log; 178 179 /** The session. */ 180 private MavenSession session; 181 182 /** The utils. */ 183 private EnforcerRuleUtils utils; 184 185 private RuntimeInformation runtimeInformation; 186 187 @Override 188 public void execute( EnforcerRuleHelper helper ) 189 throws EnforcerRuleException 190 { 191 this.log = helper.getLog(); 192 this.helper = helper; 193 194 MavenProject project; 195 try 196 { 197 // get the various expressions out of the helper. 198 199 project = (MavenProject) helper.evaluate( "${project}" ); 200 201 runtimeInformation = helper.getComponent( RuntimeInformation.class ); 202 203 DefaultLifecycles defaultLifeCycles = helper.getComponent( DefaultLifecycles.class ); 204 lifecycles = defaultLifeCycles.getLifeCycles(); 205 206 session = (MavenSession) helper.evaluate( "${session}" ); 207 pluginManager = helper.getComponent( PluginManager.class ); 208 factory = helper.getComponent( ArtifactFactory.class ); 209 resolver = helper.getComponent( ArtifactResolver.class ); 210 local = (ArtifactRepository) helper.evaluate( "${localRepository}" ); 211 212 utils = new EnforcerRuleUtils( helper ); 213 214 // get all the plugins that are bound to the specified lifecycles 215 Set<Plugin> allPlugins = getBoundPlugins( project, phases ); 216 217 // insert any additional plugins specified by the user. 218 allPlugins = addAdditionalPlugins( allPlugins, additionalPlugins ); 219 allPlugins.addAll( getProfilePlugins( project ) ); 220 221 // pull out any we should skip 222 allPlugins = 223 removeUncheckedPlugins( combineUncheckedPlugins( unCheckedPlugins, unCheckedPluginList ), allPlugins ); 224 225 // there's nothing to do here 226 if ( allPlugins.isEmpty() ) 227 { 228 log.info( "No plugin bindings found." ); 229 return; 230 } 231 else 232 { 233 log.debug( "All Plugins in use: " + allPlugins ); 234 } 235 236 // get all the plugins that are mentioned in the pom (and parents) 237 List<PluginWrapper> pluginWrappers = getAllPluginEntries( project ); 238 239 for ( PluginWrapper pluginWrapper : pluginWrappers ) 240 { 241 log.debug( "pluginWrappers: " + pluginWrapper.getGroupId() + ":" + pluginWrapper.getArtifactId() + ":" 242 + pluginWrapper.getVersion() + " source: " + pluginWrapper.getSource() ); 243 } 244 // now look for the versions that aren't valid and add to a list. 245 List<Plugin> failures = new ArrayList<Plugin>(); 246 247 for ( Plugin plugin : allPlugins ) 248 { 249 if ( !hasValidVersionSpecified( helper, plugin, pluginWrappers ) ) 250 { 251 failures.add( plugin ); 252 } 253 } 254 255 // if anything was found, log it then append the optional message. 256 if ( !failures.isEmpty() ) 257 { 258 handleMessagesToTheUser( project, failures ); 259 } 260 } 261 catch ( ExpressionEvaluationException e ) 262 { 263 throw new EnforcerRuleException( "Unable to Evaluate an Expression:" + e.getLocalizedMessage() ); 264 } 265 catch ( ComponentLookupException e ) 266 { 267 throw new EnforcerRuleException( "Unable to lookup a component:" + e.getLocalizedMessage() ); 268 } 269 catch ( Exception e ) 270 { 271 throw new EnforcerRuleException( e.getLocalizedMessage(), e ); 272 } 273 } 274 275 private void handleMessagesToTheUser( MavenProject project, List<Plugin> failures ) 276 throws EnforcerRuleException 277 { 278 StringBuilder newMsg = new StringBuilder(); 279 newMsg.append( "Some plugins are missing valid versions or depend on Maven " 280 + runtimeInformation.getMavenVersion() + " defaults:" ); 281 handleBanMessages( newMsg ); 282 newMsg.append( "\n" ); 283 for ( Plugin plugin : failures ) 284 { 285 newMsg.append( plugin.getGroupId() ); 286 newMsg.append( ":" ); 287 newMsg.append( plugin.getArtifactId() ); 288 289 try 290 { 291 newMsg.append( ". \tThe version currently in use is " ); 292 293 Plugin currentPlugin = findCurrentPlugin( plugin, project ); 294 295 if ( currentPlugin == null ) 296 { 297 newMsg.append( "unknown" ); 298 } 299 else 300 { 301 newMsg.append( currentPlugin.getVersion() ); 302 303 if ( PluginWrapper.isVersionFromDefaultLifecycleBindings( currentPlugin ).orElse( false ) ) 304 { 305 newMsg.append( " via default lifecycle bindings" ); 306 } 307 else 308 { 309 String msg = PluginWrapper.isVersionFromSuperpom( currentPlugin ) 310 .filter( b -> b ) 311 .map( t -> " via super POM" ) 312 // for Maven 3.6.0 or before (MNG-6593 / MNG-6600) 313 .orElse( " via super POM or default lifecycle bindings" ); 314 newMsg.append( msg ); 315 } 316 } 317 } 318 catch ( Exception e ) 319 { 320 // lots can go wrong here. Don't allow any issues trying to 321 // determine the issue stop me 322 log.debug( "Exception while determining plugin Version.", e ); 323 newMsg.append( ". Unable to determine the plugin version." ); 324 } 325 newMsg.append( "\n" ); 326 } 327 String message = getMessage(); 328 if ( StringUtils.isNotEmpty( message ) ) 329 { 330 newMsg.append( message ); 331 } 332 333 throw new EnforcerRuleException( newMsg.toString() ); 334 } 335 336 private void handleBanMessages( StringBuilder newMsg ) 337 { 338 if ( banLatest || banRelease || banSnapshots || banTimestamps ) 339 { 340 newMsg.append( " (" ); 341 if ( banLatest ) 342 { 343 newMsg.append( "LATEST " ); 344 } 345 if ( banRelease ) 346 { 347 newMsg.append( "RELEASE " ); 348 } 349 if ( banSnapshots || banTimestamps ) 350 { 351 newMsg.append( "SNAPSHOT " ); 352 } 353 newMsg.append( "are not allowed)" ); 354 } 355 } 356 357 /** 358 * Remove the plugins that the user doesn't want to check. 359 * 360 * @param uncheckedPlugins 361 * @param plugins 362 * @throws MojoExecutionException 363 * @return The plugins which have been removed. 364 */ 365 public Set<Plugin> removeUncheckedPlugins( Collection<String> uncheckedPlugins, Set<Plugin> plugins ) 366 throws MojoExecutionException 367 { 368 if ( uncheckedPlugins != null && !uncheckedPlugins.isEmpty() ) 369 { 370 for ( String pluginKey : uncheckedPlugins ) 371 { 372 Plugin plugin = parsePluginString( pluginKey, "UncheckedPlugins" ); 373 plugins.remove( plugin ); 374 } 375 } 376 return plugins; 377 } 378 379 /** 380 * Combines the old Collection with the new comma separated list. 381 * 382 * @param uncheckedPlugins 383 * @param uncheckedPluginsList 384 * @return List of unchecked plugins. 385 */ 386 // CHECKSTYLE_OFF: LineLength 387 public Collection<String> combineUncheckedPlugins( Collection<String> uncheckedPlugins, 388 String uncheckedPluginsList ) 389 // CHECKSTYLE_ON: LineLength 390 { 391 // if the comma list is empty, then there's nothing to do here. 392 if ( StringUtils.isNotEmpty( uncheckedPluginsList ) ) 393 { 394 // make sure there is a collection to add to. 395 if ( uncheckedPlugins == null ) 396 { 397 uncheckedPlugins = new HashSet<String>(); 398 } 399 else if ( !uncheckedPlugins.isEmpty() && log != null ) 400 { 401 log.warn( "The parameter 'unCheckedPlugins' is deprecated. Use 'unCheckedPluginList' instead" ); 402 } 403 404 uncheckedPlugins.addAll( Arrays.asList( uncheckedPluginsList.split( "," ) ) ); 405 } 406 return uncheckedPlugins; 407 } 408 409 /** 410 * Add the additional plugins if they don't exist yet. 411 * 412 * @param existing the existing 413 * @param additional the additional 414 * @return the sets the 415 * @throws MojoExecutionException the mojo execution exception 416 */ 417 public Set<Plugin> addAdditionalPlugins( Set<Plugin> existing, List<String> additional ) 418 throws MojoExecutionException 419 { 420 if ( additional != null ) 421 { 422 for ( String pluginString : additional ) 423 { 424 Plugin plugin = parsePluginString( pluginString, "AdditionalPlugins" ); 425 426 if ( existing == null ) 427 { 428 existing = new HashSet<>(); 429 existing.add( plugin ); 430 } 431 else if ( !existing.contains( plugin ) ) 432 { 433 existing.add( plugin ); 434 } 435 } 436 } 437 return existing; 438 } 439 440 /** 441 * Helper method to parse and inject a Plugin. 442 * 443 * @param pluginString 444 * @param field 445 * @throws MojoExecutionException 446 * @return the plugin 447 */ 448 protected Plugin parsePluginString( String pluginString, String field ) 449 throws MojoExecutionException 450 { 451 if ( pluginString != null ) 452 { 453 String[] pluginStrings = pluginString.split( ":" ); 454 if ( pluginStrings.length == 2 ) 455 { 456 Plugin plugin = new Plugin(); 457 plugin.setGroupId( StringUtils.strip( pluginStrings[0] ) ); 458 plugin.setArtifactId( StringUtils.strip( pluginStrings[1] ) ); 459 460 return plugin; 461 } 462 else 463 { 464 throw new MojoExecutionException( "Invalid " + field + " string: " + pluginString ); 465 } 466 } 467 else 468 { 469 throw new MojoExecutionException( "Invalid " + field + " string: " + pluginString ); 470 } 471 472 } 473 474 /** 475 * Finds the plugins that are listed in active profiles. 476 * 477 * @param project the project 478 * @return the profile plugins 479 */ 480 public Set<Plugin> getProfilePlugins( MavenProject project ) 481 { 482 Set<Plugin> result = new HashSet<>(); 483 List<Profile> profiles = project.getActiveProfiles(); 484 if ( profiles != null && !profiles.isEmpty() ) 485 { 486 for ( Profile p : profiles ) 487 { 488 BuildBase b = p.getBuild(); 489 if ( b != null ) 490 { 491 List<Plugin> plugins = b.getPlugins(); 492 if ( plugins != null ) 493 { 494 result.addAll( plugins ); 495 } 496 } 497 } 498 } 499 return result; 500 } 501 502 /** 503 * Given a plugin, this will retrieve the matching plugin artifact from the model. 504 * 505 * @param plugin plugin to lookup 506 * @param project project to search 507 * @return matching plugin, <code>null</code> if not found. 508 */ 509 protected Plugin findCurrentPlugin( Plugin plugin, MavenProject project ) 510 { 511 Plugin found = null; 512 try 513 { 514 Model model = project.getModel(); 515 Map<String, Plugin> plugins = model.getBuild().getPluginsAsMap(); 516 found = plugins.get( plugin.getKey() ); 517 } 518 catch ( NullPointerException e ) 519 { 520 // nothing to do here 521 } 522 523 if ( found == null ) 524 { 525 found = resolvePlugin( plugin, project ); 526 } 527 528 return found; 529 } 530 531 /** 532 * Resolve plugin. 533 * 534 * @param plugin the plugin 535 * @param project the project 536 * @return the plugin 537 */ 538 protected Plugin resolvePlugin( Plugin plugin, MavenProject project ) 539 { 540 541 List<ArtifactRepository> pluginRepositories = project.getPluginArtifactRepositories(); 542 Artifact artifact = factory.createPluginArtifact( plugin.getGroupId(), plugin.getArtifactId(), 543 VersionRange.createFromVersion( "LATEST" ) ); 544 545 try 546 { 547 this.resolver.resolve( artifact, pluginRepositories, this.local ); 548 plugin.setVersion( artifact.getVersion() ); 549 } 550 catch ( ArtifactResolutionException | ArtifactNotFoundException e ) 551 { 552 // What does this mean? 553 } 554 555 return plugin; 556 } 557 558 /** 559 * Gets the plugins that are bound to the defined phases. This does not find plugins bound in the pom to a phase 560 * later than the plugin is executing. 561 * 562 * @param project the project 563 * @param thePhases the phases 564 * @return the bound plugins 565 * @throws PluginNotFoundException the plugin not found exception 566 * @throws LifecycleExecutionException the lifecycle execution exception 567 * @throws IllegalAccessException the illegal access exception 568 */ 569 protected Set<Plugin> getBoundPlugins( MavenProject project, String thePhases ) 570 throws PluginNotFoundException, LifecycleExecutionException, IllegalAccessException 571 { 572 573 Set<Plugin> allPlugins = new HashSet<>(); 574 575 // lookup the bindings for all the passed in phases 576 String[] lifecyclePhases = thePhases.split( "," ); 577 for ( int i = 0; i < lifecyclePhases.length; i++ ) 578 { 579 String lifecyclePhase = lifecyclePhases[i]; 580 if ( StringUtils.isNotEmpty( lifecyclePhase ) ) 581 { 582 try 583 { 584 Lifecycle lifecycle = getLifecycleForPhase( lifecyclePhase ); 585 log.debug( "getBoundPlugins(): " + project.getId() + " " + lifecyclePhase + " " 586 + lifecycle.getId() ); 587 allPlugins.addAll( getAllPlugins( project, lifecycle ) ); 588 } 589 catch ( BuildFailureException e ) 590 { 591 // i'm going to swallow this because the 592 // user may have declared a phase that 593 // doesn't exist for every module. 594 } 595 } 596 } 597 return allPlugins; 598 } 599 600 /** 601 * Checks for valid version specified. Checks to see if the version is specified for the plugin. Can optionally ban 602 * "RELEASE" or "LATEST" even if specified. 603 * 604 * @param helper the helper 605 * @param source the source 606 * @param pluginWrappers the plugins 607 * @return true, if successful 608 */ 609 protected boolean hasValidVersionSpecified( EnforcerRuleHelper helper, Plugin source, 610 List<PluginWrapper> pluginWrappers ) 611 { 612 boolean found = false; 613 boolean status = false; 614 for ( PluginWrapper plugin : pluginWrappers ) 615 { 616 // find the matching plugin entry 617 if ( isMatchingPlugin( source, plugin ) ) 618 { 619 found = true; 620 // found the entry. now see if the version is specified 621 String version = plugin.getVersion(); 622 try 623 { 624 version = (String) helper.evaluate( version ); 625 } 626 catch ( ExpressionEvaluationException e ) 627 { 628 return false; 629 } 630 631 if ( isValidVersion( version ) ) 632 { 633 helper.getLog().debug( "checking for notEmpty and notIsWhitespace(): " + version ); 634 if ( banRelease && version.equals( "RELEASE" ) ) 635 { 636 return false; 637 } 638 639 if ( banLatest && version.equals( "LATEST" ) ) 640 { 641 return false; 642 } 643 644 if ( banSnapshots && isSnapshot( version ) ) 645 { 646 return false; 647 } 648 // the version was specified and not 649 // banned. It's ok. Keep looking through the list to make 650 // sure it's not using a banned version somewhere else. 651 652 status = true; 653 654 if ( !banRelease && !banLatest && !banSnapshots ) 655 { 656 // no need to keep looking 657 break; 658 } 659 } 660 } 661 } 662 if ( !found ) 663 { 664 helper.getLog().debug( "plugin " + source.getGroupId() + ":" + source.getArtifactId() + " not found" ); 665 } 666 return status; 667 } 668 669 private boolean isValidVersion( String version ) 670 { 671 return StringUtils.isNotEmpty( version ) && !StringUtils.isWhitespace( version ); 672 } 673 674 private boolean isMatchingPlugin( Plugin source, PluginWrapper plugin ) 675 { 676 return source.getArtifactId().equals( plugin.getArtifactId() ) 677 && source.getGroupId().equals( plugin.getGroupId() ); 678 } 679 680 /** 681 * Checks if is snapshot. 682 * 683 * @param baseVersion the base version 684 * @return true, if is snapshot 685 */ 686 protected boolean isSnapshot( String baseVersion ) 687 { 688 if ( banTimestamps ) 689 { 690 return Artifact.VERSION_FILE_PATTERN.matcher( baseVersion ).matches() 691 || baseVersion.endsWith( Artifact.SNAPSHOT_VERSION ); 692 } 693 else 694 { 695 return baseVersion.endsWith( Artifact.SNAPSHOT_VERSION ); 696 } 697 } 698 699 /* 700 * Uses borrowed lifecycle code to get a list of all plugins bound to the lifecycle. 701 */ 702 /** 703 * Gets the all plugins. 704 * 705 * @param project the project 706 * @param lifecycle the lifecycle 707 * @return the all plugins 708 * @throws PluginNotFoundException the plugin not found exception 709 * @throws LifecycleExecutionException the lifecycle execution exception 710 */ 711 private Set<Plugin> getAllPlugins( MavenProject project, Lifecycle lifecycle ) 712 throws PluginNotFoundException, LifecycleExecutionException 713 714 { 715 log.debug( "RequirePluginVersions.getAllPlugins:" ); 716 717 Set<Plugin> plugins = new HashSet<>(); 718 // first, bind those associated with the packaging 719 Map<String, String> mappings = findMappingsForLifecycle( project, lifecycle ); 720 721 for ( Map.Entry<String, String> entry : mappings.entrySet() ) 722 { 723 log.debug( " lifecycleMapping = " + entry.getKey() ); 724 String pluginsForLifecycle = (String) entry.getValue(); 725 log.debug( " plugins = " + pluginsForLifecycle ); 726 if ( StringUtils.isNotEmpty( pluginsForLifecycle ) ) 727 { 728 String pluginList[] = pluginsForLifecycle.split( "," ); 729 for ( String plugin : pluginList ) 730 { 731 plugin = StringUtils.strip( plugin ); 732 log.debug( " plugin = " + plugin ); 733 String tokens[] = plugin.split( ":" ); 734 log.debug( " GAV = " + Arrays.asList( tokens ) ); 735 736 Plugin p = new Plugin(); 737 p.setGroupId( tokens[0] ); 738 p.setArtifactId( tokens[1] ); 739 plugins.add( p ); 740 } 741 } 742 } 743 744 plugins.addAll( project.getBuildPlugins() ); 745 746 return plugins; 747 } 748 749 /* 750 * NOTE: All the code following this point was scooped from the DefaultLifecycleExecutor. There must be a better way 751 * but for now it should work. 752 */ 753 /** 754 * Gets the phase to lifecycle map. 755 * 756 * @return the phase to lifecycle map 757 * @throws LifecycleExecutionException the lifecycle execution exception 758 */ 759 public Map<String, Lifecycle> getPhaseToLifecycleMap() 760 throws LifecycleExecutionException 761 { 762 if ( phaseToLifecycleMap == null ) 763 { 764 phaseToLifecycleMap = new HashMap<>(); 765 766 for ( Lifecycle lifecycle : lifecycles ) 767 { 768 List<String> phases = lifecycle.getPhases(); 769 for ( String phase : phases ) 770 { 771 log.debug( "getPhaseToLifecycleMap(): phase: " + phase ); 772 if ( phaseToLifecycleMap.containsKey( phase ) ) 773 { 774 Lifecycle prevLifecycle = (Lifecycle) phaseToLifecycleMap.get( phase ); 775 throw new LifecycleExecutionException( "Phase '" + phase 776 + "' is defined in more than one lifecycle: '" + lifecycle.getId() + "' and '" 777 + prevLifecycle.getId() + "'" ); 778 } 779 else 780 { 781 phaseToLifecycleMap.put( phase, lifecycle ); 782 } 783 } 784 } 785 } 786 return phaseToLifecycleMap; 787 } 788 789 /** 790 * Gets the lifecycle for phase. 791 * 792 * @param phase the phase 793 * @return the lifecycle for phase 794 * @throws BuildFailureException the build failure exception 795 * @throws LifecycleExecutionException the lifecycle execution exception 796 */ 797 private Lifecycle getLifecycleForPhase( String phase ) 798 throws BuildFailureException, LifecycleExecutionException 799 { 800 Lifecycle lifecycle = getPhaseToLifecycleMap().get( phase ); 801 802 if ( lifecycle == null ) 803 { 804 throw new BuildFailureException( "Unable to find lifecycle for phase '" + phase + "'" ); 805 } 806 return lifecycle; 807 } 808 809 /** 810 * Find mappings for lifecycle. 811 * 812 * @param project the project 813 * @param lifecycle the lifecycle 814 * @return the map 815 * @throws LifecycleExecutionException the lifecycle execution exception 816 * @throws PluginNotFoundException the plugin not found exception 817 */ 818 private Map<String, String> findMappingsForLifecycle( MavenProject project, Lifecycle lifecycle ) 819 throws LifecycleExecutionException, PluginNotFoundException 820 { 821 String packaging = project.getPackaging(); 822 Map<String, String> mappings = null; 823 824 LifecycleMapping m = (LifecycleMapping) findExtension( project, LifecycleMapping.ROLE, packaging, 825 session.getSettings(), session.getLocalRepository() ); 826 if ( m != null ) 827 { 828 mappings = m.getPhases( lifecycle.getId() ); 829 } 830 831 Map<String, String> defaultMappings = lifecycle.getDefaultPhases(); 832 833 if ( mappings == null ) 834 { 835 try 836 { 837 m = helper.getComponent( LifecycleMapping.class, packaging ); 838 mappings = m.getPhases( lifecycle.getId() ); 839 } 840 catch ( ComponentLookupException e ) 841 { 842 if ( defaultMappings == null ) 843 { 844 throw new LifecycleExecutionException( "Cannot find lifecycle mapping for packaging: \'" + packaging 845 + "\'.", e ); 846 } 847 } 848 } 849 850 if ( mappings == null ) 851 { 852 if ( defaultMappings == null ) 853 { 854 throw new LifecycleExecutionException( "Cannot find lifecycle mapping for packaging: \'" + packaging 855 + "\', and there is no default" ); 856 } 857 else 858 { 859 mappings = defaultMappings; 860 } 861 } 862 863 return mappings; 864 } 865 866 /** 867 * Find extension. 868 * 869 * @param project the project 870 * @param role the role 871 * @param roleHint the role hint 872 * @param settings the settings 873 * @param localRepository the local repository 874 * @return the object 875 * @throws LifecycleExecutionException the lifecycle execution exception 876 * @throws PluginNotFoundException the plugin not found exception 877 */ 878 private Object findExtension( MavenProject project, String role, String roleHint, Settings settings, 879 ArtifactRepository localRepository ) 880 throws LifecycleExecutionException, PluginNotFoundException 881 { 882 Object pluginComponent = null; 883 884 List<Plugin> buildPlugins = project.getBuildPlugins(); 885 for ( Plugin plugin : buildPlugins ) 886 { 887 if ( plugin.isExtensions() ) 888 { 889 verifyPlugin( plugin, project, settings, localRepository ); 890 891 // TODO: if moved to the plugin manager we 892 // already have the descriptor from above 893 // and so do can lookup the container 894 // directly 895 try 896 { 897 pluginComponent = pluginManager.getPluginComponent( plugin, role, roleHint ); 898 899 if ( pluginComponent != null ) 900 { 901 break; 902 } 903 } 904 catch ( ComponentLookupException e ) 905 { 906 log.debug( "Unable to find the lifecycle component in the extension", e ); 907 } 908 catch ( PluginManagerException e ) 909 { 910 throw new LifecycleExecutionException( "Error getting extensions from the plugin '" 911 + plugin.getKey() + "': " + e.getMessage(), e ); 912 } 913 } 914 } 915 return pluginComponent; 916 } 917 918 /** 919 * Verify plugin. 920 * 921 * @param plugin the plugin 922 * @param project the project 923 * @param settings the settings 924 * @param localRepository the local repository 925 * @return the plugin descriptor 926 * @throws LifecycleExecutionException the lifecycle execution exception 927 * @throws PluginNotFoundException the plugin not found exception 928 */ 929 private PluginDescriptor verifyPlugin( Plugin plugin, MavenProject project, Settings settings, 930 ArtifactRepository localRepository ) 931 throws LifecycleExecutionException, PluginNotFoundException 932 { 933 PluginDescriptor pluginDescriptor; 934 try 935 { 936 pluginDescriptor = pluginManager.verifyPlugin( plugin, project, settings, localRepository ); 937 } 938 catch ( PluginManagerException e ) 939 { 940 throw new LifecycleExecutionException( "Internal error in the plugin manager getting plugin '" 941 + plugin.getKey() + "': " + e.getMessage(), e ); 942 } 943 catch ( PluginVersionResolutionException | InvalidVersionSpecificationException | InvalidPluginException 944 | ArtifactNotFoundException | ArtifactResolutionException | PluginVersionNotFoundException e ) 945 { 946 throw new LifecycleExecutionException( e.getMessage(), e ); 947 } 948 return pluginDescriptor; 949 } 950 951 /** 952 * Gets all plugin entries in build.plugins, build.pluginManagement.plugins, profile.build.plugins, reporting and 953 * profile.reporting in this project and all parents 954 * 955 * @param project the project 956 * @return the all plugin entries wrapped in a PluginWrapper Object 957 * @throws ArtifactResolutionException the artifact resolution exception 958 * @throws ArtifactNotFoundException the artifact not found exception 959 * @throws IOException Signals that an I/O exception has occurred. 960 * @throws XmlPullParserException the xml pull parser exception 961 */ 962 protected List<PluginWrapper> getAllPluginEntries( MavenProject project ) 963 throws ArtifactResolutionException, ArtifactNotFoundException, IOException, XmlPullParserException 964 { 965 List<PluginWrapper> plugins = new ArrayList<>(); 966 // now find all the plugin entries, either in 967 // build.plugins or build.pluginManagement.plugins, profiles.plugins and reporting 968 969 getPlugins( plugins, project.getModel() ); 970 getReportingPlugins( plugins, project.getModel() ); 971 getPluginManagementPlugins( plugins, project.getModel() ); 972 addPluginsInProfiles( plugins, project.getModel() ); 973 974 return plugins; 975 } 976 977 978 private void addPluginsInProfiles( List<PluginWrapper> plugins, Model model ) 979 { 980 List<Profile> profiles = model.getProfiles(); 981 for ( Profile profile : profiles ) 982 { 983 getProfilePlugins( plugins, model, profile ); 984 getProfileReportingPlugins( plugins, model, profile ); 985 getProfilePluginManagementPlugins( plugins, model, profile ); 986 } 987 } 988 989 private void getProfilePluginManagementPlugins( List<PluginWrapper> plugins, Model model, Profile profile ) 990 { 991 try 992 { 993 List<Plugin> modelPlugins = profile.getBuild().getPluginManagement().getPlugins(); 994 plugins.addAll( PluginWrapper.addAll( utils.resolvePlugins( modelPlugins ), banMavenDefaults ) ); 995 } 996 catch ( NullPointerException e ) 997 { 998 // guess there are no plugins here. 999 } 1000 } 1001 1002 private void getProfileReportingPlugins( List<PluginWrapper> plugins, Model model, Profile profile ) 1003 { 1004 try 1005 { 1006 List<ReportPlugin> modelReportPlugins = profile.getReporting().getPlugins(); 1007 // add the reporting plugins 1008 plugins.addAll( PluginWrapper.addAll( utils.resolveReportPlugins( modelReportPlugins ), 1009 banMavenDefaults ) ); 1010 } 1011 catch ( NullPointerException e ) 1012 { 1013 // guess there are no plugins here. 1014 } 1015 } 1016 1017 private void getProfilePlugins( List<PluginWrapper> plugins, Model model, Profile profile ) 1018 { 1019 try 1020 { 1021 List<Plugin> modelPlugins = profile.getBuild().getPlugins(); 1022 plugins.addAll( PluginWrapper.addAll( utils.resolvePlugins( modelPlugins ), banMavenDefaults ) ); 1023 } 1024 catch ( NullPointerException e ) 1025 { 1026 // guess there are no plugins here. 1027 } 1028 } 1029 1030 private void getPlugins( List<PluginWrapper> plugins, Model model ) 1031 { 1032 try 1033 { 1034 List<Plugin> modelPlugins = model.getBuild().getPlugins(); 1035 plugins.addAll( PluginWrapper.addAll( utils.resolvePlugins( modelPlugins ), banMavenDefaults ) ); 1036 } 1037 catch ( NullPointerException e ) 1038 { 1039 // guess there are no plugins here. 1040 } 1041 } 1042 1043 private void getPluginManagementPlugins( List<PluginWrapper> plugins, Model model ) 1044 { 1045 try 1046 { 1047 List<Plugin> modelPlugins = model.getBuild().getPluginManagement().getPlugins(); 1048 plugins.addAll( PluginWrapper.addAll( utils.resolvePlugins( modelPlugins ), banMavenDefaults ) ); 1049 } 1050 catch ( NullPointerException e ) 1051 { 1052 // guess there are no plugins here. 1053 } 1054 } 1055 1056 private void getReportingPlugins( List<PluginWrapper> plugins, Model model ) 1057 { 1058 try 1059 { 1060 List<ReportPlugin> modelReportPlugins = model.getReporting().getPlugins(); 1061 // add the reporting plugins 1062 plugins.addAll( PluginWrapper.addAll( utils.resolveReportPlugins( modelReportPlugins ), 1063 banMavenDefaults ) ); 1064 } 1065 catch ( NullPointerException e ) 1066 { 1067 // guess there are no plugins here. 1068 } 1069 } 1070 1071 /** 1072 * Checks if is ban latest. 1073 * 1074 * @return the banLatest 1075 */ 1076 protected boolean isBanLatest() 1077 { 1078 return this.banLatest; 1079 } 1080 1081 /** 1082 * Sets the ban latest. 1083 * 1084 * @param theBanLatest the banLatest to set 1085 */ 1086 protected void setBanLatest( boolean theBanLatest ) 1087 { 1088 this.banLatest = theBanLatest; 1089 } 1090 1091 /** 1092 * Checks if is ban release. 1093 * 1094 * @return the banRelease 1095 */ 1096 protected boolean isBanRelease() 1097 { 1098 return this.banRelease; 1099 } 1100 1101 /** 1102 * Sets the ban release. 1103 * 1104 * @param theBanRelease the banRelease to set 1105 */ 1106 protected void setBanRelease( boolean theBanRelease ) 1107 { 1108 this.banRelease = theBanRelease; 1109 } 1110 1111 /** 1112 * Gets the utils. 1113 * 1114 * @return the utils 1115 */ 1116 protected EnforcerRuleUtils getUtils() 1117 { 1118 return this.utils; 1119 } 1120 1121 /** 1122 * Sets the utils. 1123 * 1124 * @param theUtils the utils to set 1125 */ 1126 protected void setUtils( EnforcerRuleUtils theUtils ) 1127 { 1128 this.utils = theUtils; 1129 } 1130 1131 /** 1132 * Checks if is ban snapshots. 1133 * 1134 * @return the banSnapshots 1135 */ 1136 public boolean isBanSnapshots() 1137 { 1138 return this.banSnapshots; 1139 } 1140 1141 /** 1142 * Sets the ban snapshots. 1143 * 1144 * @param theBanSnapshots the banSnapshots to set 1145 */ 1146 public void setBanSnapshots( boolean theBanSnapshots ) 1147 { 1148 this.banSnapshots = theBanSnapshots; 1149 } 1150 1151 /** 1152 * Checks if is ban timestamps. 1153 * 1154 * @return the banTimestamps 1155 */ 1156 public boolean isBanTimestamps() 1157 { 1158 return this.banTimestamps; 1159 } 1160 1161 /** 1162 * Sets the ban timestamps. 1163 * 1164 * @param theBanTimestamps the banTimestamps to set 1165 */ 1166 public void setBanTimestamps( boolean theBanTimestamps ) 1167 { 1168 this.banTimestamps = theBanTimestamps; 1169 } 1170 1171 public List<String> getUnCheckedPlugins() 1172 { 1173 return unCheckedPlugins; 1174 } 1175 1176 public void setUnCheckedPlugins( List<String> unCheckedPlugins ) 1177 { 1178 this.unCheckedPlugins = unCheckedPlugins; 1179 } 1180 1181 public final void setPhases( String phases ) 1182 { 1183 this.phases = phases; 1184 } 1185 1186 public final String getPhases() 1187 { 1188 return phases; 1189 } 1190 1191 public final void setAdditionalPlugins( List<String> additionalPlugins ) 1192 { 1193 this.additionalPlugins = additionalPlugins; 1194 } 1195 1196 public final List<String> getAdditionalPlugins() 1197 { 1198 return additionalPlugins; 1199 } 1200}