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/<name>/}). 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());
+ }
+}