This is an automated email from the ASF dual-hosted git repository.

hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new d578273b83 issue #7652: skip Nexus browse for ASF/Central Maven group 
URLs (#7653)
d578273b83 is described below

commit d578273b83c6d36d0a17a068e98a261a55c665d0
Author: Matt Casters <[email protected]>
AuthorDate: Tue Jul 28 09:25:47 2026 +0200

    issue #7652: skip Nexus browse for ASF/Central Maven group URLs (#7653)
    
    Live discovery only uses Nexus REST for …/repository/<name>/ bases. ASF
    public and Maven Central remain install-only so marketplace refresh after
    install no longer logs a stack error for repository 'asf'.
---
 .../catalog/NexusRepositoryBrowser.java            | 21 ++++++++-
 .../hop/marketplace/catalog/PluginDiscovery.java   | 28 ++++++++---
 .../catalog/NexusRepositoryBrowserTest.java        | 55 ++++++++++++++++++++++
 3 files changed, 95 insertions(+), 9 deletions(-)

diff --git 
a/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/catalog/NexusRepositoryBrowser.java
 
b/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/catalog/NexusRepositoryBrowser.java
index de49c971e3..f1d829751f 100644
--- 
a/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/catalog/NexusRepositoryBrowser.java
+++ 
b/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/catalog/NexusRepositoryBrowser.java
@@ -45,6 +45,16 @@ public final class NexusRepositoryBrowser {
 
   private NexusRepositoryBrowser() {}
 
+  /**
+   * Whether {@code repositoryUrl} looks like a Sonatype Nexus 3 Maven base 
({@code
+   * …/repository/&lt;name&gt;/}). Classic Maven group URLs (ASF public, 
Central) are not browsable
+   * this way — use the bundled Apache catalog and/or optional definition 
{@code plugins} metadata
+   * instead.
+   */
+  public static boolean isNexusBrowseUrl(String repositoryUrl) {
+    return StringUtils.isNotBlank(extractRepositoryName(repositoryUrl));
+  }
+
   public static List<OptionalPluginInfo> browse(
       MarketplaceRepository repository, String textFilter, ILogChannel log) 
throws HopException {
     if (repository == null || StringUtils.isBlank(repository.getUrl())) {
@@ -53,8 +63,15 @@ public final class NexusRepositoryBrowser {
     String repoName = extractRepositoryName(repository.getUrl());
     String nexusBase = extractNexusBase(repository.getUrl());
     if (StringUtils.isBlank(repoName) || StringUtils.isBlank(nexusBase)) {
-      throw new HopException(
-          "Cannot derive Nexus host/repository name from URL: " + 
repository.getUrl());
+      // ASF groups/public and Maven Central are install endpoints, not Nexus 
REST search.
+      if (log != null) {
+        log.logDetailed(
+            "Skipping Nexus zip browse for repository '"
+                + repository.getId()
+                + "' (URL is not a Nexus …/repository/<name>/ base): "
+                + repository.getUrl());
+      }
+      return List.of();
     }
 
     HttpClient client =
diff --git 
a/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/catalog/PluginDiscovery.java
 
b/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/catalog/PluginDiscovery.java
index b6fbdf8110..e9d20adc33 100644
--- 
a/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/catalog/PluginDiscovery.java
+++ 
b/plugins/misc/marketplace/src/main/java/org/apache/hop/marketplace/catalog/PluginDiscovery.java
@@ -95,12 +95,14 @@ public final class PluginDiscovery {
           }
         } catch (Exception e) {
           if (log != null) {
-            log.logError(
-                "Marketplace discovery failed for repository '"
+            // Network/Nexus errors: keep listing other sources; full stack 
only when detailed.
+            log.logBasic(
+                "Marketplace discovery skipped for repository '"
                     + repo.getId()
                     + "': "
-                    + e.getMessage(),
-                e);
+                    + e.getMessage());
+            log.logDetailed(
+                "Marketplace discovery failure for repository '" + 
repo.getId() + "'", e);
           }
         }
       }
@@ -270,14 +272,26 @@ public final class PluginDiscovery {
     if (StringUtils.isNotBlank(repo.getCatalogUrl())) {
       live = RemotePluginCatalog.load(repo);
       live = RemotePluginCatalog.filter(live, repo, filter);
-    } else {
+    } else if (NexusRepositoryBrowser.isNexusBrowseUrl(repo.getUrl())) {
       live = NexusRepositoryBrowser.browse(repo, filter, log);
+    } else {
+      // ASF public / Maven Central: install-only layout; Apache optionals 
come from the bundled
+      // catalog. Optional definition plugins still surface for browse=true 
non-Nexus repos.
+      live = List.of();
+      if (log != null) {
+        log.logDetailed(
+            "Repository '"
+                + repo.getId()
+                + "' is not a Nexus browse URL; using definition plugin 
metadata only if present.");
+      }
     }
 
-    // If live listing failed empty but definition has explicit plugins, use 
those (not a cache —
+    // If live listing is empty but definition has explicit plugins, use those 
(not a cache —
     // author-supplied list in the YAML).
     if (live.isEmpty() && repo.getPlugins() != null && 
!repo.getPlugins().isEmpty()) {
-      return RemotePluginCatalog.filter(repo.getPlugins(), repo, filter);
+      List<OptionalPluginInfo> fromDef =
+          RemotePluginCatalog.filter(repo.getPlugins(), repo, filter);
+      return enrichWithDefinitionMetadata(fromDef, repo);
     }
 
     return enrichWithDefinitionMetadata(live, repo);
diff --git 
a/plugins/misc/marketplace/src/test/java/org/apache/hop/marketplace/catalog/NexusRepositoryBrowserTest.java
 
b/plugins/misc/marketplace/src/test/java/org/apache/hop/marketplace/catalog/NexusRepositoryBrowserTest.java
new file mode 100644
index 0000000000..8b987a3770
--- /dev/null
+++ 
b/plugins/misc/marketplace/src/test/java/org/apache/hop/marketplace/catalog/NexusRepositoryBrowserTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package org.apache.hop.marketplace.catalog;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.apache.hop.marketplace.config.MarketplaceRepository;
+import org.junit.jupiter.api.Test;
+
+class NexusRepositoryBrowserTest {
+
+  @Test
+  void asfPublicGroupIsNotNexusBrowseUrl() {
+    assertFalse(
+        NexusRepositoryBrowser.isNexusBrowseUrl(
+            "https://repository.apache.org/content/groups/public/";));
+    
assertFalse(NexusRepositoryBrowser.isNexusBrowseUrl("https://repo1.maven.org/maven2/";));
+  }
+
+  @Test
+  void nexusRepositoryPathIsBrowsable() {
+    assertTrue(
+        NexusRepositoryBrowser.isNexusBrowseUrl(
+            
"https://repository.data-hopper.com/repository/hop-community-plugins/";));
+    assertEquals(
+        "hop-community-plugins",
+        NexusRepositoryBrowser.extractRepositoryName(
+            
"https://repository.data-hopper.com/repository/hop-community-plugins/";));
+  }
+
+  @Test
+  void browseAsfReturnsEmptyWithoutThrowing() throws Exception {
+    MarketplaceRepository asf =
+        new MarketplaceRepository("asf", 
"https://repository.apache.org/content/groups/public/";);
+    asf.setBrowse(true);
+    assertTrue(NexusRepositoryBrowser.browse(asf, null, null).isEmpty());
+  }
+}

Reply via email to