You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by kw...@apache.org on 2025/07/30 14:49:21 UTC

(maven-scm) branch feature/improve-jgit-push-result-handling created (now 91bececb3)

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

kwin pushed a change to branch feature/improve-jgit-push-result-handling
in repository https://gitbox.apache.org/repos/asf/maven-scm.git


      at 91bececb3 JGit: Propagate exceptions when pushing tags/branches

This branch includes the following new commits:

     new 91bececb3 JGit: Propagate exceptions when pushing tags/branches

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(maven-scm) 01/01: JGit: Propagate exceptions when pushing tags/branches

Posted by kw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch feature/improve-jgit-push-result-handling
in repository https://gitbox.apache.org/repos/asf/maven-scm.git

commit 91bececb3d5731d2414e28de0081c7394c1b1121
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Wed Jul 30 16:49:11 2025 +0200

    JGit: Propagate exceptions when pushing tags/branches
    
    Add tests for all Git providers for failing push operations
    This closes #1253
---
 .../maven/scm/provider/git/GitScmTestUtils.java    | 54 ++++++++++++++++++++++
 .../command/branch/GitBranchCommandTckTest.java    | 18 ++++++++
 .../git/command/tag/GitTagCommandTckTest.java      | 18 ++++++++
 .../git/command/untag/GitUntagCommandTckTest.java  | 29 ++++++++++++
 .../scm/provider/git/jgit/command/JGitUtils.java   | 15 ++++--
 .../provider/git/jgit/command/PushException.java   | 40 ++++++++++++++++
 .../git/jgit/command/branch/JGitBranchCommand.java |  6 +++
 .../jgit/command/checkin/JGitCheckInCommand.java   | 30 ++++--------
 .../git/jgit/command/tag/JGitTagCommand.java       |  6 +++
 .../git/jgit/command/untag/JGitUntagCommand.java   | 13 +++++-
 10 files changed, 205 insertions(+), 24 deletions(-)

diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/GitScmTestUtils.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/GitScmTestUtils.java
index 2a4ce35e4..7a02040e3 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/GitScmTestUtils.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/GitScmTestUtils.java
@@ -102,4 +102,58 @@ public static void setDefaultGitConfig(File repositoryRootFile) {
             e.printStackTrace();
         }
     }
+
+    /**
+     * Sets up a pre-receive git hook that rejects all commits for the given repository (server-side).
+     * This is useful for testing scenarios where you want to simulate a repository
+     * that doesn't allow any new commits.
+     * This hook is <a href="https://github.com/eclipse-jgit/jgit/issues/192">not supported by JGit</a>.
+     *
+     *
+     * @param repositoryRootFile the root directory of the git repository
+     * @throws IOException if there's an error creating or writing the hook file
+     */
+    public static void setupRejectAllCommitsPreReceiveHook(File repositoryRootFile) throws IOException {
+        setupRejectAllCommitsHook(repositoryRootFile, true, "pre-receive");
+    }
+
+    /**
+     * Sets up a pre-push git hook that rejects all commits for the given repository (client-side).
+     * This is useful for testing scenarios where you want to simulate a repository
+     * that doesn't allow any new commits.
+     *
+     * @param repositoryRootFile the root directory of the git repository
+     * @throws IOException if there's an error creating or writing the hook file
+     */
+    public static void setupRejectAllCommitsPrePushHook(File workspaceRoot) throws IOException {
+        setupRejectAllCommitsHook(workspaceRoot, false, "pre-push");
+    }
+
+    private static void setupRejectAllCommitsHook(
+            File repositoryOrWorkspaceRootFile, boolean isServerSide, String hookName) throws IOException {
+        File hooksDir;
+        if (!isServerSide) {
+            // For client-side hooks, we use the .git/hooks directory
+            hooksDir = new File(repositoryOrWorkspaceRootFile, ".git/hooks");
+        } else {
+            // For server-side hooks, we use the hooks directory directly
+            hooksDir = new File(repositoryOrWorkspaceRootFile, "hooks");
+        }
+        if (!hooksDir.exists() && !hooksDir.mkdirs()) {
+            throw new IOException("Failed to create hooks directory: " + hooksDir.getAbsolutePath());
+        }
+
+        File preReceiveHook = new File(hooksDir, hookName);
+        try (FileWriter fw = new FileWriter(preReceiveHook)) {
+            fw.write("#!/bin/sh\n");
+            fw.write("# Pre-receive hook that rejects all commits\n");
+            fw.write("echo \"Error: This repository is configured to reject all commits\"\n");
+            fw.write("exit 1\n");
+        }
+
+        // Make the hook executable (on Unix-like systems)
+        if (!preReceiveHook.setExecutable(true)) {
+            throw new IOException("Could not make pre-receive hook executable at: " + preReceiveHook.getAbsolutePath());
+        }
+    }
 }
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/branch/GitBranchCommandTckTest.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/branch/GitBranchCommandTckTest.java
index 0dd33b0ec..68941bdc1 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/branch/GitBranchCommandTckTest.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/branch/GitBranchCommandTckTest.java
@@ -20,10 +20,15 @@
 
 import java.io.File;
 
+import org.apache.maven.scm.ScmFileSet;
+import org.apache.maven.scm.command.branch.BranchScmResult;
 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
 import org.apache.maven.scm.provider.git.GitScmTestUtils;
 import org.apache.maven.scm.repository.ScmRepository;
 import org.apache.maven.scm.tck.command.branch.BranchCommandTckTest;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
 
 /**
  * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
@@ -43,4 +48,17 @@ protected CheckOutScmResult checkOut(File workingDirectory, ScmRepository reposi
             GitScmTestUtils.setDefaultGitConfig(workingDirectory);
         }
     }
+
+    @Test
+    public void testPushBranchRejected() throws Exception {
+        String branch = getBranch();
+
+        GitScmTestUtils.setupRejectAllCommitsPrePushHook(getWorkingCopy());
+        @SuppressWarnings("deprecation")
+        BranchScmResult branchResult = getScmManager()
+                .getProviderByUrl(getScmUrl())
+                .branch(getScmRepository(), new ScmFileSet(getWorkingCopy()), branch);
+
+        assertFalse("Branch should not have been pushed", branchResult.isSuccess());
+    }
 }
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/tag/GitTagCommandTckTest.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/tag/GitTagCommandTckTest.java
index 21640a5f9..b151574de 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/tag/GitTagCommandTckTest.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/tag/GitTagCommandTckTest.java
@@ -20,10 +20,15 @@
 
 import java.io.File;
 
+import org.apache.maven.scm.ScmFileSet;
 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
+import org.apache.maven.scm.command.tag.TagScmResult;
 import org.apache.maven.scm.provider.git.GitScmTestUtils;
 import org.apache.maven.scm.repository.ScmRepository;
 import org.apache.maven.scm.tck.command.tag.TagCommandTckTest;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
 
 /**
  * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
@@ -43,4 +48,17 @@ protected CheckOutScmResult checkOut(File workingDirectory, ScmRepository reposi
             GitScmTestUtils.setDefaultGitConfig(workingDirectory);
         }
     }
+
+    @Test
+    public void testPushTagRejected() throws Exception {
+        String tag = getTagName();
+
+        GitScmTestUtils.setupRejectAllCommitsPrePushHook(getWorkingCopy());
+        @SuppressWarnings("deprecation")
+        TagScmResult tagResult = getScmManager()
+                .getProviderByUrl(getScmUrl())
+                .tag(getScmRepository(), new ScmFileSet(getWorkingCopy()), tag);
+
+        assertFalse("Tag should not have been pushed", tagResult.isSuccess());
+    }
 }
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/untag/GitUntagCommandTckTest.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/untag/GitUntagCommandTckTest.java
index 652460cb2..acf5abed3 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/untag/GitUntagCommandTckTest.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/untag/GitUntagCommandTckTest.java
@@ -20,10 +20,20 @@
 
 import java.io.File;
 
+import org.apache.maven.scm.CommandParameter;
+import org.apache.maven.scm.CommandParameters;
+import org.apache.maven.scm.ScmFileSet;
+import org.apache.maven.scm.ScmTagParameters;
 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
+import org.apache.maven.scm.command.tag.TagScmResult;
+import org.apache.maven.scm.command.untag.UntagScmResult;
+import org.apache.maven.scm.provider.ScmProvider;
 import org.apache.maven.scm.provider.git.GitScmTestUtils;
 import org.apache.maven.scm.repository.ScmRepository;
 import org.apache.maven.scm.tck.command.untag.UntagCommandTckTest;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
 
 /** {@inheritDoc} */
 public abstract class GitUntagCommandTckTest extends UntagCommandTckTest {
@@ -40,4 +50,23 @@ protected CheckOutScmResult checkOut(File workingDirectory, ScmRepository reposi
             GitScmTestUtils.setDefaultGitConfig(workingDirectory);
         }
     }
+
+    @Test
+    public void testPushTagDeletionRejected() throws Exception {
+        String tag = getTagName();
+        ScmProvider scmProvider = getScmManager().getProviderByUrl(getScmUrl());
+        ScmRepository scmRepository = getScmRepository();
+        ScmFileSet files = new ScmFileSet(getWorkingCopy());
+        TagScmResult tagResult = scmProvider.tag(scmRepository, files, tag, new ScmTagParameters());
+
+        assertResultIsSuccess(tagResult);
+
+        GitScmTestUtils.setupRejectAllCommitsPrePushHook(getWorkingCopy());
+        CommandParameters params = new CommandParameters();
+        params.setString(CommandParameter.TAG_NAME, tag);
+
+        UntagScmResult untagResult = scmProvider.untag(scmRepository, files, params);
+
+        assertFalse("Tag deletion should not have been pushed", untagResult.isSuccess());
+    }
 }
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitUtils.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitUtils.java
index deac415fa..17a0e6664 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitUtils.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/JGitUtils.java
@@ -166,17 +166,26 @@ public static Iterable<PushResult> push(
             Git git,
             GitScmProviderRepository repo,
             RefSpec refSpec,
+            Set<RemoteRefUpdate.Status> successfulStatuses,
             Optional<TransportConfigCallback> transportConfigCallback)
-            throws GitAPIException {
+            throws PushException {
         CredentialsProvider credentials = prepareSession(git, repo);
         PushCommand command = git.push().setRefSpecs(refSpec).setCredentialsProvider(credentials);
         transportConfigCallback.ifPresent(command::setTransportConfigCallback);
 
-        Iterable<PushResult> pushResultList = command.call();
+        Iterable<PushResult> pushResultList;
+        try {
+            pushResultList = command.call();
+        } catch (GitAPIException e) {
+            throw new PushException(repo.getPushUrlWithMaskedPassword(), e);
+        }
         for (PushResult pushResult : pushResultList) {
             Collection<RemoteRefUpdate> ru = pushResult.getRemoteUpdates();
             for (RemoteRefUpdate remoteRefUpdate : ru) {
-                LOGGER.info(remoteRefUpdate.getStatus() + " - " + remoteRefUpdate);
+                if (!successfulStatuses.contains(remoteRefUpdate.getStatus())) {
+                    throw new PushException(repo.getPushUrlWithMaskedPassword(), remoteRefUpdate);
+                }
+                LOGGER.debug("Push succeeded {}", remoteRefUpdate);
             }
         }
         return pushResultList;
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/PushException.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/PushException.java
new file mode 100644
index 000000000..f7c1158ba
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/PushException.java
@@ -0,0 +1,40 @@
+/*
+ * 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.maven.scm.provider.git.jgit.command;
+
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.transport.RemoteRefUpdate;
+
+/**
+ * Exception thrown when a push operation fails in JGit.
+ * This is a custom exception that extends GitAPIException to provide more context
+ * about the failure during a push operation.
+ */
+public class PushException extends Exception {
+
+    private static final long serialVersionUID = 1L;
+
+    public PushException(String url, RemoteRefUpdate update) {
+        super("Failed to push reference to " + url + ": " + update);
+    }
+
+    public PushException(String url, GitAPIException e) {
+        super("Failed to push reference to " + url + ": " + e.getMessage(), e);
+    }
+}
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/branch/JGitBranchCommand.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/branch/JGitBranchCommand.java
index 05ad6986c..1fcc74fe2 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/branch/JGitBranchCommand.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/branch/JGitBranchCommand.java
@@ -19,6 +19,7 @@
 package org.apache.maven.scm.provider.git.jgit.command.branch;
 
 import java.util.ArrayList;
+import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -38,6 +39,7 @@
 import org.apache.maven.scm.provider.git.jgit.command.CustomizableSshSessionFactoryCommand;
 import org.apache.maven.scm.provider.git.jgit.command.JGitTransportConfigCallback;
 import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
+import org.apache.maven.scm.provider.git.jgit.command.PushException;
 import org.apache.maven.scm.provider.git.jgit.command.ScmProviderAwareSshdSessionFactory;
 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
 import org.eclipse.jgit.api.Git;
@@ -49,6 +51,7 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.RefSpec;
+import org.eclipse.jgit.transport.RemoteRefUpdate;
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.slf4j.Logger;
 
@@ -105,6 +108,7 @@ protected ScmResult executeBranchCommand(
                         git,
                         (GitScmProviderRepository) repo,
                         new RefSpec(Constants.R_HEADS + branch),
+                        EnumSet.of(RemoteRefUpdate.Status.OK, RemoteRefUpdate.Status.UP_TO_DATE),
                         Optional.of(transportConfigCallback));
             }
 
@@ -126,6 +130,8 @@ protected ScmResult executeBranchCommand(
 
             return new BranchScmResult("JGit branch", files);
 
+        } catch (PushException e) {
+            return new BranchScmResult("JGit branch", "Failed to push changes: " + e.getMessage(), "", false);
         } catch (Exception e) {
             throw new ScmException("JGit branch failed!", e);
         }
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/checkin/JGitCheckInCommand.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/checkin/JGitCheckInCommand.java
index 5b5ae5930..124c59f1f 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/checkin/JGitCheckInCommand.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/checkin/JGitCheckInCommand.java
@@ -22,6 +22,7 @@
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
@@ -41,6 +42,7 @@
 import org.apache.maven.scm.provider.git.jgit.command.CustomizableSshSessionFactoryCommand;
 import org.apache.maven.scm.provider.git.jgit.command.JGitTransportConfigCallback;
 import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
+import org.apache.maven.scm.provider.git.jgit.command.PushException;
 import org.apache.maven.scm.provider.git.jgit.command.ScmProviderAwareSshdSessionFactory;
 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
 import org.eclipse.jgit.api.AddCommand;
@@ -51,7 +53,6 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.UserConfig;
 import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.transport.PushResult;
 import org.eclipse.jgit.transport.RefSpec;
 import org.eclipse.jgit.transport.RemoteRefUpdate;
 import org.slf4j.Logger;
@@ -176,23 +177,17 @@ public CheckInScmResult executeCommand(ScmProviderRepository repo, ScmFileSet fi
                 TransportConfigCallback transportConfigCallback = new JGitTransportConfigCallback(
                         sshSessionFactorySupplier.apply((GitScmProviderRepository) repo, logger));
 
-                Iterable<PushResult> pushResultList = JGitUtils.push(
-                        git, (GitScmProviderRepository) repo, refSpec, Optional.of(transportConfigCallback));
-
-                for (PushResult pushResult : pushResultList) {
-                    for (RemoteRefUpdate remoteRefUpdate : pushResult.getRemoteUpdates()) {
-                        if (!isSuccessStatus(remoteRefUpdate.getStatus())) {
-                            return new CheckInScmResult(
-                                    "JGit checkin",
-                                    "The git-push command failed, with status: " + remoteRefUpdate.getStatus(),
-                                    remoteRefUpdate.getMessage(),
-                                    false);
-                        }
-                    }
-                }
+                JGitUtils.push(
+                        git,
+                        (GitScmProviderRepository) repo,
+                        refSpec,
+                        EnumSet.of(RemoteRefUpdate.Status.OK, RemoteRefUpdate.Status.UP_TO_DATE),
+                        Optional.of(transportConfigCallback));
             }
 
             return new CheckInScmResult("JGit checkin", checkedInFiles);
+        } catch (PushException e) {
+            return new CheckInScmResult("JGit checkin", "Failed to push changes: " + e.getMessage(), "", false);
         } catch (Exception e) {
             throw new ScmException("JGit checkin failure!", e);
         } finally {
@@ -212,11 +207,6 @@ protected CheckInScmResult executeCheckInCommand(
         return executeCommand(repo, fileSet, parameters);
     }
 
-    private boolean isSuccessStatus(RemoteRefUpdate.Status remoteRefUpdateStatus) {
-        return remoteRefUpdateStatus == RemoteRefUpdate.Status.OK
-                || remoteRefUpdateStatus == RemoteRefUpdate.Status.UP_TO_DATE;
-    }
-
     private static final class UserInfo {
 
         final String name;
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/tag/JGitTagCommand.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/tag/JGitTagCommand.java
index 075ed4b32..6aa921a43 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/tag/JGitTagCommand.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/tag/JGitTagCommand.java
@@ -19,6 +19,7 @@
 package org.apache.maven.scm.provider.git.jgit.command.tag;
 
 import java.util.ArrayList;
+import java.util.EnumSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.function.BiFunction;
@@ -36,6 +37,7 @@
 import org.apache.maven.scm.provider.git.jgit.command.CustomizableSshSessionFactoryCommand;
 import org.apache.maven.scm.provider.git.jgit.command.JGitTransportConfigCallback;
 import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
+import org.apache.maven.scm.provider.git.jgit.command.PushException;
 import org.apache.maven.scm.provider.git.jgit.command.ScmProviderAwareSshdSessionFactory;
 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
 import org.eclipse.jgit.api.Git;
@@ -45,6 +47,7 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.RefSpec;
+import org.eclipse.jgit.transport.RemoteRefUpdate;
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.slf4j.Logger;
 
@@ -111,6 +114,7 @@ public ScmResult executeTagCommand(
                         git,
                         (GitScmProviderRepository) repo,
                         new RefSpec(Constants.R_TAGS + escapedTagName),
+                        EnumSet.of(RemoteRefUpdate.Status.OK, RemoteRefUpdate.Status.UP_TO_DATE),
                         Optional.of(transportConfigCallback));
             }
 
@@ -131,6 +135,8 @@ public ScmResult executeTagCommand(
             walk.close();
 
             return new TagScmResult("JGit tag", taggedFiles);
+        } catch (PushException e) {
+            return new TagScmResult("JGit tag", "Failed to push tag: " + e.getMessage(), "", false);
         } catch (Exception e) {
             throw new ScmException("JGit tag failure!", e);
         } finally {
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/untag/JGitUntagCommand.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/untag/JGitUntagCommand.java
index 6fea4bff3..bfd676b21 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/untag/JGitUntagCommand.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/untag/JGitUntagCommand.java
@@ -19,6 +19,7 @@
 package org.apache.maven.scm.provider.git.jgit.command.untag;
 
 import java.util.Collection;
+import java.util.EnumSet;
 import java.util.Optional;
 import java.util.function.BiFunction;
 
@@ -33,6 +34,7 @@
 import org.apache.maven.scm.provider.git.jgit.command.CustomizableSshSessionFactoryCommand;
 import org.apache.maven.scm.provider.git.jgit.command.JGitTransportConfigCallback;
 import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
+import org.apache.maven.scm.provider.git.jgit.command.PushException;
 import org.apache.maven.scm.provider.git.jgit.command.ScmProviderAwareSshdSessionFactory;
 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
 import org.eclipse.jgit.api.Git;
@@ -88,7 +90,14 @@ protected ScmResult executeUntagCommand(
                 logger.info("push delete tag [" + escapedTagName + "] to remote...");
 
                 Iterable<PushResult> pushResultList = JGitUtils.push(
-                        git, (GitScmProviderRepository) repository, refSpec, Optional.of(transportConfigCallback));
+                        git,
+                        (GitScmProviderRepository) repository,
+                        refSpec,
+                        EnumSet.of(
+                                RemoteRefUpdate.Status.OK,
+                                RemoteRefUpdate.Status.UP_TO_DATE,
+                                RemoteRefUpdate.Status.NON_EXISTING),
+                        Optional.of(transportConfigCallback));
                 if (logger.isInfoEnabled()) {
                     for (PushResult pushResult : pushResultList) {
                         Collection<RemoteRefUpdate> ru = pushResult.getRemoteUpdates();
@@ -100,6 +109,8 @@ protected ScmResult executeUntagCommand(
             }
 
             return new UntagScmResult("JGit tagDelete");
+        } catch (PushException e) {
+            return new UntagScmResult("JGit tagDelete", "Failed to push tag deletion: " + e.getMessage(), "", false);
         } catch (Exception e) {
             throw new ScmException("JGit tagDelete failure!", e);
         } finally {