[MNG-6326] Make the build fail if core extensions can not be loaded (#648)
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
index ead1331..89f3833 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
@@ -743,6 +743,7 @@
 
     private List<CoreExtensionEntry> loadCoreExtensions( CliRequest cliRequest, ClassRealm containerRealm,
                                                          Set<String> providedArtifacts )
+            throws Exception
     {
         if ( cliRequest.multiModuleProjectDirectory == null )
         {
@@ -755,75 +756,62 @@
             return Collections.emptyList();
         }
 
+        List<CoreExtension> extensions = readCoreExtensionsDescriptor( extensionsFile );
+        if ( extensions.isEmpty() )
+        {
+            return Collections.emptyList();
+        }
+
+        ContainerConfiguration cc = new DefaultContainerConfiguration() //
+            .setClassWorld( cliRequest.classWorld ) //
+            .setRealm( containerRealm ) //
+            .setClassPathScanning( PlexusConstants.SCANNING_INDEX ) //
+            .setAutoWiring( true ) //
+            .setJSR250Lifecycle( true ) //
+            .setName( "maven" );
+
+        DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule()
+        {
+            @Override
+            protected void configure()
+            {
+                bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory );
+            }
+        } );
+
         try
         {
-            List<CoreExtension> extensions = readCoreExtensionsDescriptor( extensionsFile );
-            if ( extensions.isEmpty() )
-            {
-                return Collections.emptyList();
-            }
+            container.setLookupRealm( null );
 
-            ContainerConfiguration cc = new DefaultContainerConfiguration() //
-                .setClassWorld( cliRequest.classWorld ) //
-                .setRealm( containerRealm ) //
-                .setClassPathScanning( PlexusConstants.SCANNING_INDEX ) //
-                .setAutoWiring( true ) //
-                .setJSR250Lifecycle( true ) //
-                .setName( "maven" );
+            container.setLoggerManager( plexusLoggerManager );
 
-            DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule()
-            {
-                @Override
-                protected void configure()
-                {
-                    bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory );
-                }
-            } );
+            container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
 
-            try
-            {
-                container.setLookupRealm( null );
+            Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
 
-                container.setLoggerManager( plexusLoggerManager );
+            executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class );
 
-                container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
+            configurationProcessors = container.lookupMap( ConfigurationProcessor.class );
 
-                Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
+            configure( cliRequest );
 
-                executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class );
+            MavenExecutionRequest request = DefaultMavenExecutionRequest.copy( cliRequest.request );
 
-                configurationProcessors = container.lookupMap( ConfigurationProcessor.class );
+            populateRequest( cliRequest, request );
 
-                configure( cliRequest );
+            request = executionRequestPopulator.populateDefaults( request );
 
-                MavenExecutionRequest request = DefaultMavenExecutionRequest.copy( cliRequest.request );
+            BootstrapCoreExtensionManager resolver = container.lookup( BootstrapCoreExtensionManager.class );
 
-                populateRequest( cliRequest, request );
+            return Collections.unmodifiableList( resolver.loadCoreExtensions( request, providedArtifacts,
+                                                                              extensions ) );
 
-                request = executionRequestPopulator.populateDefaults( request );
-
-                BootstrapCoreExtensionManager resolver = container.lookup( BootstrapCoreExtensionManager.class );
-
-                return Collections.unmodifiableList( resolver.loadCoreExtensions( request, providedArtifacts,
-                                                                                  extensions ) );
-
-            }
-            finally
-            {
-                executionRequestPopulator = null;
-                container.dispose();
-            }
         }
-        catch ( RuntimeException e )
+        finally
         {
-            // runtime exceptions are most likely bugs in maven, let them bubble up to the user
-            throw e;
+            executionRequestPopulator = null;
+            container.dispose();
         }
-        catch ( Exception e )
-        {
-            slf4jLogger.warn( "Failed to read extensions descriptor from '{}'", extensionsFile, e );
-        }
-        return Collections.emptyList();
     }
 
     private List<CoreExtension> readCoreExtensionsDescriptor( File extensionsFile )
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java
index e0107e0..041b9f5 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java
@@ -128,18 +128,29 @@
 
     private List<Artifact> resolveExtension( CoreExtension extension, RepositorySystemSession repoSession,
                                              List<RemoteRepository> repositories, DependencyFilter dependencyFilter )
-        throws PluginResolutionException
+        throws ExtensionResolutionException
     {
-        Plugin plugin = new Plugin();
-        plugin.setGroupId( extension.getGroupId() );
-        plugin.setArtifactId( extension.getArtifactId() );
-        plugin.setVersion( extension.getVersion() );
+        try
+        {
+            // TODO: enhance the PluginDependenciesResolver to provide a
+            // TODO:    resolveCoreExtension method which uses a CoreExtension
+            // TODO:    object instead of a Plugin as this makes no sense
+            Plugin plugin = new Plugin();
+            plugin.setGroupId( extension.getGroupId() );
+            plugin.setArtifactId( extension.getArtifactId() );
+            plugin.setVersion( extension.getVersion() );
 
-        DependencyNode root =
-            pluginDependenciesResolver.resolveCoreExtension( plugin, dependencyFilter, repositories, repoSession );
-        PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
-        root.accept( nlg );
+            DependencyNode root = pluginDependenciesResolver
+                    .resolveCoreExtension( plugin, dependencyFilter, repositories, repoSession );
+            PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
+            root.accept( nlg );
 
-        return nlg.getArtifacts( false );
+            return nlg.getArtifacts( false );
+        }
+        catch ( PluginResolutionException e )
+        {
+            throw new ExtensionResolutionException( extension, e.getCause() );
+        }
     }
+
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/internal/ExtensionResolutionException.java b/maven-embedder/src/main/java/org/apache/maven/cli/internal/ExtensionResolutionException.java
new file mode 100644
index 0000000..4f8cff9
--- /dev/null
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/internal/ExtensionResolutionException.java
@@ -0,0 +1,47 @@
+package org.apache.maven.cli.internal;
+
+/*
+ * 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 org.apache.maven.cli.internal.extension.model.CoreExtension;
+
+/**
+ * Exception occurring trying to resolve a plugin.
+ *
+ * @author <a href="mailto:brett@apache.org">Brett Porter</a>
+ */
+public class ExtensionResolutionException
+    extends Exception
+{
+
+    private final CoreExtension extension;
+
+    public ExtensionResolutionException( CoreExtension extension, Throwable cause )
+    {
+        super( "Extension " + extension.getId() + " or one of its dependencies could not be resolved: "
+                        + cause.getMessage(), cause );
+        this.extension = extension;
+    }
+
+    public CoreExtension getExtension()
+    {
+        return extension;
+    }
+
+}
diff --git a/maven-embedder/src/main/mdo/core-extensions.mdo b/maven-embedder/src/main/mdo/core-extensions.mdo
index e523d5a..8a74aab 100644
--- a/maven-embedder/src/main/mdo/core-extensions.mdo
+++ b/maven-embedder/src/main/mdo/core-extensions.mdo
@@ -83,6 +83,32 @@
           <type>String</type>
         </field>
       </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>1.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * Gets the identifier of the extension.
+     *
+     * @return The extension id in the form {@code <groupId>:<artifactId>:<version>}, never {@code null}.
+     */
+    public String getId()
+    {
+        StringBuilder id = new StringBuilder( 128 );
+
+        id.append( ( getGroupId() == null ) ? "[unknown-group-id]" : getGroupId() );
+        id.append( ":" );
+        id.append( ( getArtifactId() == null ) ? "[unknown-artifact-id]" : getArtifactId() );
+        id.append( ":" );
+        id.append( ( getVersion() == null ) ? "[unknown-version]" : getVersion() );
+
+        return id.toString();
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
     </class>
   </classes>
 </model>