GoogleCloudPlatform / artifact-registry-maven-tools

Apache License 2.0
24 stars 22 forks source link

How to use as `<mirrorOf>*</mirrorOf>`? #83

Open eriksw opened 1 year ago

eriksw commented 1 year ago

I'd like to take advantage of the recently released Remote and Virtual repositories features of Artifact Registry in order to make my builds resilient against intermittent connectivity to or throttling by Maven Central.

Currently, even if I forcibly populate my ~/.m2/repository with the full dependency tree of the plugin, if I then put in a ~/.m2/settings.xml specifying artifactregistry://... as a <mirrorOf>*</mirrorOf>, I get the error below:

[INFO] Scanning for projects...
[ERROR] [ERROR] Some problems were encountered while processing the POMs:
[ERROR] Unresolveable build extension: Plugin com.google.cloud.artifactregistry:artifactregistry-maven-wagon:2.2.0 or one of its dependencies could not be resolved: Failed to read artifact descriptor for com.google.cloud.artifactregistry:artifactregistry-maven-wagon:jar:2.2.0 @
 @
[ERROR] The build could not read 1 project -> [Help 1]
[ERROR]
[ERROR]   The project myproject:java-root:1.0.0-SNAPSHOT (.../pom.xml) has 1 error
[ERROR]     Unresolveable build extension: Plugin com.google.cloud.artifactregistry:artifactregistry-maven-wagon:2.2.0 or one of its dependencies could not be resolved: Failed to read artifact descriptor for com.google.cloud.artifactregistry:artifactregistry-maven-wagon:jar:2.2.0: Could not transfer artifact com.google.cloud.artifactregistry:artifactregistry-maven-wagon:pom:2.2.0 from/to artifact-registry (artifactregistry://us-maven.pkg.dev/MYPROJECT/MYVIRTUAL): Cannot access artifactregistry://us-maven.pkg.dev/MYPROJECT/MYVIRTUAL with type default using the available connector factories: BasicRepositoryConnectorFactory: Cannot access artifactregistry://us-maven.pkg.dev/MYPROJECT/MYVIRTUAL using the registered transporter factories: WagonTransporterFactory: java.util.NoSuchElementException
[ERROR]           role: org.apache.maven.wagon.Wagon
[ERROR]       roleHint: artifactregistry
[ERROR]     -> [Help 2]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/ProjectBuildingException
[ERROR] [Help 2] http://cwiki.apache.org/confluence/display/MAVEN/PluginManagerException

Can you please provide documentation of how to achieve the following?:

  1. How to use an Artifact Registry Virtual Repository (including a mirror of central) as <mirrorOf>*</mirrorOf>
  2. How to install artifactregistry-maven-wagon on a system with zero requests to central.
lindsayismith commented 1 year ago

Hi Erik, great questions. I've been looking at this, and I have an initial solution, but always open to feedback.

First - setting up Maven to mirror everything through AR. Here's a settings file that will do this, but uses basic auth with a short-lived token to authenticate to AR:

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">

<!-- This will ensure that all requests go through ar - but requires that we have an updated token in the auth section. 
    That token only lasts an hour.
    To update token:
       export ARTIFACT_REGISTRY_TOKEN=$(gcloud auth print-access-token)
-->

 <mirrors>
    <mirror>
      <id>central-mirror</id>
      <name>AR Maven Central mirror</name>
      <url>https://us-west1-maven.pkg.dev/my-project-name/my-repository-name</url>
      <mirrorOf>*</mirrorOf>
    </mirror>
  </mirrors> 

   <servers>
      <server>
        <id>central-mirror</id>
        <username>oauth2accesstoken</username>
        <password>${env.ARTIFACT_REGISTRY_TOKEN}</password>
      </server>
  </servers>
</settings>

This makes use of the fact that Artifact Registry can take a simple username/password, where the username is 'oauth2accesstoken' and the password is a short-lived token. You have to run something like this before the build, to populate the environment variable with your token:

export ARTIFACT_REGISTRY_TOKEN=$(gcloud auth print-access-token)

Running your build with these settings will pull all dependencies through the mirror you defined. The downside is that the token will expire after an hour.

You can also use this setup to bootstrap your repository with the wagon, which will help this. You can manually install the wagon like this:

mvn dependency:get -Dartifact=com.google.cloud.artifactregistry:artifactregistry-maven-wagon:2.2.1

This will pull the wagon, and all it's dependencies, via the mirror you configured in the settings file, into the local repository. Make sure you use version 2.2.1, it has slimmed down dependencies compared to the prior versions.

Then, you can configure your mirror to use the wagon with two steps:

  1. Settings file:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">

  <mirrors>
    <mirror>
      <id>central-mirror</id>
      <name>AR Maven Central mirror</name>
      <url>artifactregistry://us-west1-maven.pkg.dev/my-project-name/my-repo-name</url>
      <mirrorOf>*</mirrorOf>
    </mirror>
  </mirrors> 

</settings>
  1. Add an extensions file to load the wagon.

This file needs to go in your project folder, in <Project Pom Root>/.mvn/extensions.xml:

<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.0.0 http://maven.apache.org/xsd/core-extensions-1.0.0.xsd">
  <extension>
    <groupId>com.google.cloud.artifactregistry</groupId>
    <artifactId>artifactregistry-maven-wagon</artifactId>
    <version>2.2.1</version>
  </extension>
</extensions>

Now, when you build your project, it will load the wagon from the local repo, and then the build will be able to talk to AR using the wagon. The wagon will provide authentication to AR from the environment, instead of using a short lived token.

recena commented 1 year ago

This was precisely what I did. I also tried to provide the extension like this mvn -Dmaven.ext.class.path=extension.jar.

In any case, I'm facing this WARN message:

Downloading from orchid-central: artifactregistry://us-east1-maven.pkg.dev/orchid-128412/central/org/infinispan/infinispan-bom/14.0.12.Final/infinispan-bom-14.0.12.Final.pom
[WARNING] Could not apply configuration for orchid-central to Wagon com.google.cloud.artifactregistry.wagon.ArtifactRegistryWagon
org.codehaus.plexus.component.configurator.ComponentConfigurationException: Cannot find 'httpConfiguration' in class com.google.cloud.artifactregistry.wagon.ArtifactRegistryWagon
    at org.eclipse.sisu.plexus.CompositeBeanHelper.setProperty (CompositeBeanHelper.java:252)
    at org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter.processConfiguration (ObjectWithFieldsConverter.java:101)
    at org.eclipse.aether.internal.transport.wagon.PlexusWagonConfigurator$WagonComponentConfigurator.configureComponent (PlexusWagonConfigurator.java:89)
    at org.codehaus.plexus.component.configurator.AbstractComponentConfigurator.configureComponent (AbstractComponentConfigurator.java:44)
    at org.codehaus.plexus.component.configurator.AbstractComponentConfigurator.configureComponent (AbstractComponentConfigurator.java:37)
    at org.eclipse.aether.internal.transport.wagon.PlexusWagonConfigurator.configure (PlexusWagonConfigurator.java:74)
    at org.eclipse.aether.transport.wagon.WagonTransporter.connectWagon (WagonTransporter.java:287)
    at org.eclipse.aether.transport.wagon.WagonTransporter.pollWagon (WagonTransporter.java:323)
    at org.eclipse.aether.transport.wagon.WagonTransporter.execute (WagonTransporter.java:364)
    at org.eclipse.aether.transport.wagon.WagonTransporter.get (WagonTransporter.java:348)
    at org.eclipse.aether.connector.basic.BasicRepositoryConnector$GetTaskRunner.runTask (BasicRepositoryConnector.java:482)
    at org.eclipse.aether.connector.basic.BasicRepositoryConnector$TaskRunner.run (BasicRepositoryConnector.java:414)
    at org.eclipse.aether.connector.basic.BasicRepositoryConnector.get (BasicRepositoryConnector.java:260)
    at org.eclipse.aether.internal.impl.DefaultArtifactResolver.performDownloads (DefaultArtifactResolver.java:522)
    at org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve (DefaultArtifactResolver.java:435)
    at org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts (DefaultArtifactResolver.java:259)
    at org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifact (DefaultArtifactResolver.java:242)
    at org.eclipse.aether.internal.impl.DefaultRepositorySystem.resolveArtifact (DefaultRepositorySystem.java:277)
    at org.apache.maven.project.ProjectModelResolver.resolveModel (ProjectModelResolver.java:172)
    at org.apache.maven.model.building.DefaultModelBuilder.importDependencyManagement (DefaultModelBuilder.java:1178)
    at org.apache.maven.model.building.DefaultModelBuilder.build (DefaultModelBuilder.java:486)
    at org.apache.maven.model.building.DefaultModelBuilder.build (DefaultModelBuilder.java:410)
    at org.apache.maven.model.building.DefaultModelBuilder.importDependencyManagement (DefaultModelBuilder.java:1208)
    at org.apache.maven.model.building.DefaultModelBuilder.build (DefaultModelBuilder.java:486)
    at org.apache.maven.model.building.DefaultModelBuilder.build (DefaultModelBuilder.java:455)
    at org.apache.maven.project.DefaultProjectBuilder.build (DefaultProjectBuilder.java:612)
    at org.apache.maven.project.DefaultProjectBuilder.build (DefaultProjectBuilder.java:375)
    at org.apache.maven.graph.DefaultGraphBuilder.collectProjects (DefaultGraphBuilder.java:349)
    at org.apache.maven.graph.DefaultGraphBuilder.getProjectsForMavenReactor (DefaultGraphBuilder.java:340)
    at org.apache.maven.graph.DefaultGraphBuilder.build (DefaultGraphBuilder.java:76)
    at org.apache.maven.DefaultMaven.buildGraph (DefaultMaven.java:448)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:197)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:173)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:101)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:906)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:283)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:206)
    at jdk.internal.reflect.DirectMethodHandleAccessor.invoke (DirectMethodHandleAccessor.java:104)
    at java.lang.reflect.Method.invoke (Method.java:578)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:283)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:226)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:407)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:348)
Downloaded from orchid-central: artifactregistry://us-east1-maven.pkg.dev/orchid-128412/central/org/infinispan/infinispan-bom/14.0.12.Final/infinispan-bom-14.0.12.Final.pom (24 kB at 20 kB/s)
Downloading from orchid-central: artifactregistry://us-east1-maven.pkg.dev/orchid-128412/central/org/infinispan/infinispan-build-configuration-parent/14.0.12.Final/infinispan-build-configuration-parent-14.0.12.Final.pom

Maven environment:

% mvn --version
Apache Maven 3.9.3 (21122926829f1ead511c958d89bd2f672198ae9f)
Maven home: /Users/mrecena/.sdkman/candidates/maven/current
Java version: 20.0.2, vendor: Oracle Corporation, runtime: /Users/mrecena/.sdkman/candidates/java/20.0.2-open
Default locale: en_ES, platform encoding: UTF-8
OS name: "mac os x", version: "13.4.1", arch: "aarch64", family: "mac"
yanis-incepto commented 4 months ago

Hello, do you have any news on this ? Still got the problem and proposed solution doesn't work, i'm not able to connect to GAR using ARTIFACT_REGISTRY_TOKEN