You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sl...@apache.org on 2026/09/04 21:40:28 UTC
(maven-resolver) 01/01: Fail the PUT when a checksum upload fails on 1.9.x
This is an automated email from the ASF dual-hosted git repository.
slachiewicz pushed a commit to branch agent/resolver-19x-checksum-upload-failure
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit b42f3a15bf8831cdeed0c06ea604f3a79de4a708
Author: Sylwester Lachiewicz <sl...@apache.org>
AuthorDate: Fri Sep 4 23:40:13 2026 +0200
Fail the PUT when a checksum upload fails on 1.9.x
A checksum that could not be uploaded was logged at WARN and the transfer
reported success, leaving the artifact published without checksums. The
transfer now fails unless aether.connector.basic.failOnChecksumUploadFailure
is set to false, per repository or globally.
---
.../connector/basic/BasicRepositoryConnector.java | 43 ++++++++++++++++------
src/site/markdown/configuration.md | 1 +
2 files changed, 33 insertions(+), 11 deletions(-)
diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java
index 3047a0ba0..08e401d95 100644
--- a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java
+++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java
@@ -82,6 +82,16 @@ final class BasicRepositoryConnector implements RepositoryConnector {
private static final String CONFIG_PROP_PARALLEL_PUT = "aether.connector.basic.parallelPut";
+ /**
+ * Whether a failed checksum upload fails the whole PUT transfer. When enabled (default), a deploy is atomic
+ * across the artifact bytes and their checksums: if a checksum cannot be calculated or its upload fails, the
+ * transfer fails, instead of the remote repository ending up with an artifact published without checksums.
+ * When disabled, checksum upload failures are only logged at WARN level, as in earlier releases. Supports a
+ * repository id suffix.
+ */
+ private static final String CONFIG_PROP_FAIL_ON_CHECKSUM_UPLOAD_FAILURE =
+ "aether.connector.basic.failOnChecksumUploadFailure";
+
private static final Logger LOGGER = LoggerFactory.getLogger(BasicRepositoryConnector.class);
private final Map<String, ProvidedChecksumsSource> providedChecksumsSources;
@@ -106,6 +116,8 @@ final class BasicRepositoryConnector implements RepositoryConnector {
private final boolean persistedChecksums;
+ private final boolean failOnChecksumUploadFailure;
+
private Executor executor;
private final AtomicBoolean closed;
@@ -145,6 +157,11 @@ final class BasicRepositoryConnector implements RepositoryConnector {
session,
ConfigurationProperties.DEFAULT_PERSISTED_CHECKSUMS,
ConfigurationProperties.PERSISTED_CHECKSUMS);
+ failOnChecksumUploadFailure = ConfigUtils.getBoolean(
+ session,
+ true,
+ CONFIG_PROP_FAIL_ON_CHECKSUM_UPLOAD_FAILURE + "." + repository.getId(),
+ CONFIG_PROP_FAIL_ON_CHECKSUM_UPLOAD_FAILURE);
}
private Executor getExecutor(int tasks) {
@@ -572,43 +589,47 @@ final class BasicRepositoryConnector implements RepositoryConnector {
* @param file source
* @param bytes transformed data from file or {@code null}
*/
- private void uploadChecksums(File file, byte[] bytes) {
+ private void uploadChecksums(File file, byte[] bytes) throws Exception {
if (checksumLocations.isEmpty()) {
return;
}
+ Map<String, String> sumsByAlgo;
try {
ArrayList<ChecksumAlgorithmFactory> algorithms = new ArrayList<>();
for (RepositoryLayout.ChecksumLocation checksumLocation : checksumLocations) {
algorithms.add(checksumLocation.getChecksumAlgorithmFactory());
}
- Map<String, String> sumsByAlgo;
if (bytes != null) {
sumsByAlgo = ChecksumAlgorithmHelper.calculate(bytes, algorithms);
} else {
sumsByAlgo = ChecksumAlgorithmHelper.calculate(file, algorithms);
}
-
- for (RepositoryLayout.ChecksumLocation checksumLocation : checksumLocations) {
- uploadChecksum(
- checksumLocation.getLocation(),
- sumsByAlgo.get(checksumLocation
- .getChecksumAlgorithmFactory()
- .getName()));
- }
} catch (IOException e) {
LOGGER.warn("Failed to upload checksums for {}", file, e);
throw new UncheckedIOException(e);
}
+
+ for (RepositoryLayout.ChecksumLocation checksumLocation : checksumLocations) {
+ uploadChecksum(
+ checksumLocation.getLocation(),
+ sumsByAlgo.get(
+ checksumLocation.getChecksumAlgorithmFactory().getName()));
+ }
}
- private void uploadChecksum(URI location, Object checksum) {
+ private void uploadChecksum(URI location, Object checksum) throws Exception {
try {
if (checksum instanceof Exception) {
throw (Exception) checksum;
}
transporter.put(new PutTask(location).setDataString((String) checksum));
} catch (Exception e) {
+ if (failOnChecksumUploadFailure) {
+ // the deploy is only complete once the checksums are in place next to the artifact
+ LOGGER.error("Failed to upload checksum to {}", location, e);
+ throw e;
+ }
LOGGER.warn("Failed to upload checksum to {}", location, e);
}
}
diff --git a/src/site/markdown/configuration.md b/src/site/markdown/configuration.md
index abee016a2..7591129c2 100644
--- a/src/site/markdown/configuration.md
+++ b/src/site/markdown/configuration.md
@@ -33,6 +33,7 @@ under the License.
| `aether.conflictResolver.verbose` | boolean | Flag controlling the conflict resolver's verbose mode. [...]
| `aether.connector.basic.threads` or `maven.artifact.threads` | int | Number of threads to use for uploading/downloading. [...]
| `aether.connector.basic.parallelPut` | boolean | Enables or disables parallel PUT processing (parallel deploys) on basic connector globally or per remote repository. When disabled, connector behaves exactly as in Maven 3.8.x did: GETs are parallel while PUTs are sequential. When enabled, connector will issue first PUT individually and only once completed the rest of PUTs in parallel. [...]
+| `aether.connector.basic.failOnChecksumUploadFailure` | boolean | Whether a failed checksum upload fails the whole PUT transfer. When disabled, checksum upload failures are only logged. | `true` | yes |
| `aether.connector.classpath.loader` | ClassLoader | `ClassLoader` from which resources should be retrieved which start with the `classpath:` protocol. [...]
| `aether.connector.connectTimeout` | long | Connect timeout in milliseconds. [...]
| `aether.connector.http.bind.address` | String | Set the outgoing interface (globally or per remote repository). Valid values are local accessible IP addresses or host names. The default will use the system's default route. Invalid addresses will result in HttpTransport creation failure. [...]