You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mi...@apache.org on 2018/12/29 23:30:39 UTC

[maven-scm] 01/02: [SCM-318] Allow tags to be removed with Git implementation

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

michaelo pushed a commit to branch SCM-318
in repository https://gitbox.apache.org/repos/asf/maven-scm.git

commit 30b2b3b72f9143b25c3865e62d95c436aaf3ca9a
Author: Chris Hennick <49...@users.noreply.github.com>
AuthorDate: Tue Jul 31 00:08:53 2018 -0700

    [SCM-318] Allow tags to be removed with Git implementation
    
    This closes #79
---
 .../scm/command/untag/AbstractUntagCommand.java    |  52 +++++++++
 .../maven/scm/command/untag/UntagScmResult.java    |  47 ++++++++
 .../maven/scm/provider/AbstractScmProvider.java    |   9 ++
 .../org/apache/maven/scm/provider/ScmProvider.java |  13 +++
 .../org/apache/maven/scm/plugin/UnTagMojo.java     |  82 ++++++++++++++
 .../org/apache/maven/scm/plugin/UnTagMojoTest.java | 123 +++++++++++++++++++++
 .../src/test/resources/mojos/untag/checkout.xml    |  36 ++++++
 .../src/test/resources/mojos/untag/untag.xml       |  34 ++++++
 maven-scm-providers/maven-scm-provider-vss/pom.xml |   7 ++
 .../scm/provider/git/AbstractGitScmProvider.java   |  12 ++
 .../maven/scm/provider/git/TestGitScmProvider.java |   4 +
 .../scm/provider/git/gitexe/GitExeScmProvider.java |   5 +
 .../git/gitexe/command/untag/GitUntagCommand.java  | 120 ++++++++++++++++++++
 .../scm/provider/git/jgit/JGitScmProvider.java     |   8 ++
 .../git/jgit/command/untag/JGitUntagCommand.java   |  61 ++++++++++
 .../maven-scm-provider-svn-commons/pom.xml         |   7 ++
 16 files changed, 620 insertions(+)

diff --git a/maven-scm-api/src/main/java/org/apache/maven/scm/command/untag/AbstractUntagCommand.java b/maven-scm-api/src/main/java/org/apache/maven/scm/command/untag/AbstractUntagCommand.java
new file mode 100644
index 0000000..3e8dc07
--- /dev/null
+++ b/maven-scm-api/src/main/java/org/apache/maven/scm/command/untag/AbstractUntagCommand.java
@@ -0,0 +1,52 @@
+package org.apache.maven.scm.command.untag;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.scm.CommandParameter;
+import org.apache.maven.scm.CommandParameters;
+import org.apache.maven.scm.ScmException;
+import org.apache.maven.scm.ScmFileSet;
+import org.apache.maven.scm.ScmResult;
+import org.apache.maven.scm.ScmTagParameters;
+import org.apache.maven.scm.command.AbstractCommand;
+import org.apache.maven.scm.provider.ScmProviderRepository;
+
+/**
+ * @author <a href="https://pr0methean.github.io">Chris Hennick</a>
+ *
+ */
+public abstract class AbstractUntagCommand
+    extends AbstractCommand
+{
+    protected abstract ScmResult executeUntagCommand(ScmProviderRepository repository,
+        ScmFileSet fileSet, String tagName)
+        throws ScmException;    
+    
+    /** {@inheritDoc} */
+    public ScmResult executeCommand( ScmProviderRepository repository, ScmFileSet fileSet,
+                                     CommandParameters parameters )
+        throws ScmException
+    {
+        String tagName = parameters.getString( CommandParameter.TAG_NAME );
+
+        return executeUntagCommand( repository, fileSet, tagName );
+    }
+    
+}
diff --git a/maven-scm-api/src/main/java/org/apache/maven/scm/command/untag/UntagScmResult.java b/maven-scm-api/src/main/java/org/apache/maven/scm/command/untag/UntagScmResult.java
new file mode 100644
index 0000000..c389ca8
--- /dev/null
+++ b/maven-scm-api/src/main/java/org/apache/maven/scm/command/untag/UntagScmResult.java
@@ -0,0 +1,47 @@
+package org.apache.maven.scm.command.untag;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.scm.ScmResult;
+
+/**
+ * @author <a href="https://pr0methean.github.io">Chris Hennick</a>
+ *
+ */
+public class UntagScmResult
+    extends ScmResult
+{
+    private static final long serialVersionUID = -5068975000282095635L;
+
+    public UntagScmResult( String commandLine, String providerMessage, String commandOutput, boolean success )
+    {
+        super( commandLine, providerMessage, commandOutput, success );
+    }
+
+    public UntagScmResult(String commandLine)
+    {
+        super( commandLine, null, null, true );
+    }
+
+    public UntagScmResult(ScmResult result)
+    {
+        super( result );
+    }
+}
diff --git a/maven-scm-api/src/main/java/org/apache/maven/scm/provider/AbstractScmProvider.java b/maven-scm-api/src/main/java/org/apache/maven/scm/provider/AbstractScmProvider.java
index dfcc88d..f0b1bb9 100644
--- a/maven-scm-api/src/main/java/org/apache/maven/scm/provider/AbstractScmProvider.java
+++ b/maven-scm-api/src/main/java/org/apache/maven/scm/provider/AbstractScmProvider.java
@@ -49,6 +49,7 @@ import org.apache.maven.scm.command.remove.RemoveScmResult;
 import org.apache.maven.scm.command.status.StatusScmResult;
 import org.apache.maven.scm.command.tag.TagScmResult;
 import org.apache.maven.scm.command.unedit.UnEditScmResult;
+import org.apache.maven.scm.command.untag.UntagScmResult;
 import org.apache.maven.scm.command.update.UpdateScmResult;
 import org.apache.maven.scm.log.ScmLogDispatcher;
 import org.apache.maven.scm.log.ScmLogger;
@@ -899,6 +900,14 @@ public abstract class AbstractScmProvider
         return new UnEditScmResult( "", null, null, true );
     }
 
+    @Override
+    public UntagScmResult untag(ScmRepository repository, ScmFileSet fileSet,
+        CommandParameters parameters)
+        throws ScmException {
+        getLogger().warn( "Deleting tags not implemented for " + this.getScmType() );
+        return new UntagScmResult( "", null, null, true );
+    }
+
     /**
      * {@inheritDoc}
      *
diff --git a/maven-scm-api/src/main/java/org/apache/maven/scm/provider/ScmProvider.java b/maven-scm-api/src/main/java/org/apache/maven/scm/provider/ScmProvider.java
index a2d005f..a59f708 100644
--- a/maven-scm-api/src/main/java/org/apache/maven/scm/provider/ScmProvider.java
+++ b/maven-scm-api/src/main/java/org/apache/maven/scm/provider/ScmProvider.java
@@ -45,6 +45,7 @@ import org.apache.maven.scm.command.remove.RemoveScmResult;
 import org.apache.maven.scm.command.status.StatusScmResult;
 import org.apache.maven.scm.command.tag.TagScmResult;
 import org.apache.maven.scm.command.unedit.UnEditScmResult;
+import org.apache.maven.scm.command.untag.UntagScmResult;
 import org.apache.maven.scm.command.update.UpdateScmResult;
 import org.apache.maven.scm.log.ScmLogger;
 import org.apache.maven.scm.repository.ScmRepository;
@@ -642,6 +643,18 @@ public interface ScmProvider
         throws ScmException;
 
     /**
+     * Deletes a tag.
+     *
+     * @param repository the source control system
+     * @param fileSet    a fileset with the relevant working directory as basedir
+     * @param parameters
+     * @return
+     * @throws ScmException if any
+     */
+    UntagScmResult untag(ScmRepository repository, ScmFileSet fileSet, CommandParameters parameters)
+        throws ScmException;
+
+    /**
      * Tag (or label in some systems) will tag the source file with a certain tag
      *
      * @param repository the source control system
diff --git a/maven-scm-plugin/src/main/java/org/apache/maven/scm/plugin/UnTagMojo.java b/maven-scm-plugin/src/main/java/org/apache/maven/scm/plugin/UnTagMojo.java
new file mode 100644
index 0000000..eddf35b
--- /dev/null
+++ b/maven-scm-plugin/src/main/java/org/apache/maven/scm/plugin/UnTagMojo.java
@@ -0,0 +1,82 @@
+package org.apache.maven.scm.plugin;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.scm.CommandParameter;
+import org.apache.maven.scm.CommandParameters;
+import org.apache.maven.scm.ScmException;
+import org.apache.maven.scm.ScmTagParameters;
+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.repository.ScmRepository;
+
+/**
+ * Delete a tag.
+ *
+ * @author <a href="https://pr0methean.github.io">Chris Hennick</a>
+ */
+@Mojo( name = "untag", aggregator = true )
+public class UnTagMojo
+    extends AbstractScmMojo
+{
+    /**
+     * The tag name.
+     */
+    @Parameter( property = "tag", required = true )
+    private String tag;
+
+    /** {@inheritDoc} */
+    public void execute()
+        throws MojoExecutionException
+    {
+        super.execute();
+
+        try
+        {
+            ScmRepository repository = getScmRepository();
+            ScmProvider provider = getScmManager().getProviderByRepository( repository );
+
+            String finalTag = provider.sanitizeTagName( tag );
+            getLog().info( "Final Tag Name: '" + finalTag + "'" );
+
+            CommandParameters parameters = new CommandParameters();
+            parameters.setString( CommandParameter.TAG_NAME, finalTag );
+
+            UntagScmResult result = provider.untag( repository, getFileSet(), parameters );
+
+            checkResult( result );
+        }
+        catch ( IOException e )
+        {
+            throw new MojoExecutionException( "Cannot run untag command : ", e );
+        }
+        catch ( ScmException e )
+        {
+            throw new MojoExecutionException( "Cannot run untag command : ", e );
+        }
+    }
+}
diff --git a/maven-scm-plugin/src/test/java/org/apache/maven/scm/plugin/UnTagMojoTest.java b/maven-scm-plugin/src/test/java/org/apache/maven/scm/plugin/UnTagMojoTest.java
new file mode 100644
index 0000000..14d9073
--- /dev/null
+++ b/maven-scm-plugin/src/test/java/org/apache/maven/scm/plugin/UnTagMojoTest.java
@@ -0,0 +1,123 @@
+package org.apache.maven.scm.plugin;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import org.apache.maven.plugin.testing.AbstractMojoTestCase;
+import org.apache.maven.scm.ScmTestCase;
+import org.apache.maven.scm.provider.svn.SvnScmTestUtils;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
+ *
+ */
+public class UnTagMojoTest
+    extends AbstractMojoTestCase
+{
+    File checkoutDir;
+
+    File repository;
+
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        checkoutDir = getTestFile( "target/checkout" );
+
+        FileUtils.forceDelete( checkoutDir );
+
+        repository = getTestFile( "target/repository" );
+
+        FileUtils.forceDelete( repository );
+
+        if ( !ScmTestCase.isSystemCmd( SvnScmTestUtils.SVNADMIN_COMMAND_LINE ) )
+        {
+            System.err.println( "'" + SvnScmTestUtils.SVNADMIN_COMMAND_LINE
+                + "' is not a system command. Ignored setUp." );
+            return;
+        }
+
+        SvnScmTestUtils.initializeRepository( repository );
+
+        CheckoutMojo checkoutMojo = (CheckoutMojo) lookupMojo( "checkout", getTestFile(
+            "src/test/resources/mojos/checkout/checkoutWithConnectionUrl.xml" ) );
+        checkoutMojo.setWorkingDirectory( new File( getBasedir() ) );
+
+        String connectionUrl = checkoutMojo.getConnectionUrl();
+        connectionUrl = StringUtils.replace( connectionUrl, "${basedir}", getBasedir() );
+        connectionUrl = StringUtils.replace( connectionUrl, "\\", "/" );
+        checkoutMojo.setConnectionUrl( connectionUrl );
+
+        checkoutMojo.setCheckoutDirectory( checkoutDir );
+
+        checkoutMojo.execute();
+    }
+
+    public void testUnTag()
+        throws Exception
+    {
+        if ( !ScmTestCase.isSystemCmd( SvnScmTestUtils.SVNADMIN_COMMAND_LINE ) )
+        {
+            System.err.println( "'" + SvnScmTestUtils.SVNADMIN_COMMAND_LINE
+                + "' is not a system command. Ignored " + getName() + "." );
+            return;
+        }
+
+        UnTagMojo mojo = (UnTagMojo) lookupMojo( "untag", getTestFile( "src/test/resources/mojos/untag/untag.xml" ) );
+        mojo.setWorkingDirectory( checkoutDir );
+
+        String connectionUrl = mojo.getConnectionUrl();
+        connectionUrl = StringUtils.replace( connectionUrl, "${basedir}", getBasedir() );
+        connectionUrl = StringUtils.replace( connectionUrl, "\\", "/" );
+        mojo.setConnectionUrl( connectionUrl );
+
+        mojo.execute();
+
+        if ( !ScmTestCase.isSystemCmd( SvnScmTestUtils.SVN_COMMAND_LINE ) )
+        {
+            System.err.println( "'" + SvnScmTestUtils.SVN_COMMAND_LINE
+                + "' is not a system command. Ignored " + getName() + "." );
+            return;
+        }
+
+        CheckoutMojo checkoutMojo =
+            (CheckoutMojo) lookupMojo( "checkout", getTestFile( "src/test/resources/mojos/untag/checkout.xml" ) );
+        checkoutMojo.setWorkingDirectory( new File( getBasedir() ) );
+
+        connectionUrl = checkoutMojo.getConnectionUrl();
+        connectionUrl = StringUtils.replace( connectionUrl, "${basedir}", getBasedir() );
+        connectionUrl = StringUtils.replace( connectionUrl, "\\", "/" );
+        checkoutMojo.setConnectionUrl( connectionUrl );
+
+        File tagCheckoutDir = getTestFile( "target/tags/mytag" );
+        if ( tagCheckoutDir.exists() )
+        {
+            FileUtils.deleteDirectory( tagCheckoutDir );
+        }
+        checkoutMojo.setCheckoutDirectory( tagCheckoutDir );
+
+        assertFalse( new File( tagCheckoutDir, "pom.xml" ).exists() );
+        checkoutMojo.execute();
+        assertTrue( new File( tagCheckoutDir, "pom.xml" ).exists() );
+    }
+}
diff --git a/maven-scm-plugin/src/test/resources/mojos/untag/checkout.xml b/maven-scm-plugin/src/test/resources/mojos/untag/checkout.xml
new file mode 100644
index 0000000..b8b8022
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/mojos/untag/checkout.xml
@@ -0,0 +1,36 @@
+<!--
+  ~ 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.
+  -->
+
+<project>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-scm-plugin</artifactId>
+        <configuration>
+          <settings implementation="org.apache.maven.settings.Settings"/>
+          <checkoutDirectory>target/tags/mytag</checkoutDirectory>
+          <connectionType>connection</connectionType>
+          <connectionUrl>scm:svn:file:///${basedir}/target/repository/trunk</connectionUrl>
+          <scmVersionType>tag</scmVersionType>
+          <scmVersion>mytag</scmVersion>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
\ No newline at end of file
diff --git a/maven-scm-plugin/src/test/resources/mojos/untag/untag.xml b/maven-scm-plugin/src/test/resources/mojos/untag/untag.xml
new file mode 100644
index 0000000..dafa0f3
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/mojos/untag/untag.xml
@@ -0,0 +1,34 @@
+<!--
+  ~ 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.
+  -->
+
+<project>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-scm-plugin</artifactId>
+        <configuration>
+          <settings implementation="org.apache.maven.settings.Settings"/>
+          <connectionUrl>scm:svn:file:///${basedir}/target/repository/trunk</connectionUrl>
+          <connectionType>connection</connectionType>
+          <tag>mytag</tag>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
\ No newline at end of file
diff --git a/maven-scm-providers/maven-scm-provider-vss/pom.xml b/maven-scm-providers/maven-scm-provider-vss/pom.xml
index 2649303..e8deab1 100644
--- a/maven-scm-providers/maven-scm-provider-vss/pom.xml
+++ b/maven-scm-providers/maven-scm-provider-vss/pom.xml
@@ -21,6 +21,13 @@
 
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven.scm</groupId>
+      <artifactId>maven-scm-provider-vss</artifactId>
+      <version>1.9.4</version>
+    </dependency>
+  </dependencies>
 
   <parent>
     <groupId>org.apache.maven.scm</groupId>
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/main/java/org/apache/maven/scm/provider/git/AbstractGitScmProvider.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/main/java/org/apache/maven/scm/provider/git/AbstractGitScmProvider.java
index dbeadac..4fc054c 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/main/java/org/apache/maven/scm/provider/git/AbstractGitScmProvider.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/main/java/org/apache/maven/scm/provider/git/AbstractGitScmProvider.java
@@ -40,11 +40,13 @@ import org.apache.maven.scm.command.remoteinfo.RemoteInfoScmResult;
 import org.apache.maven.scm.command.remove.RemoveScmResult;
 import org.apache.maven.scm.command.status.StatusScmResult;
 import org.apache.maven.scm.command.tag.TagScmResult;
+import org.apache.maven.scm.command.untag.UntagScmResult;
 import org.apache.maven.scm.command.update.UpdateScmResult;
 import org.apache.maven.scm.provider.AbstractScmProvider;
 import org.apache.maven.scm.provider.ScmProviderRepository;
 import org.apache.maven.scm.provider.git.command.GitCommand;
 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
+import org.apache.maven.scm.repository.ScmRepository;
 import org.apache.maven.scm.repository.ScmRepositoryException;
 import org.apache.maven.scm.repository.UnknownRepositoryStructure;
 
@@ -272,6 +274,16 @@ public abstract class AbstractGitScmProvider
         return (TagScmResult) executeCommand( getTagCommand(), repository, fileSet, parameters );
     }
 
+    protected abstract GitCommand getUntagCommand();
+
+    /** {@inheritDoc} */
+    public UntagScmResult untag( ScmRepository repository, ScmFileSet fileSet, CommandParameters parameters )
+        throws ScmException
+    {
+        return (UntagScmResult) executeCommand( getUntagCommand(),
+            repository.getProviderRepository(), fileSet, parameters);
+    }
+
     protected abstract GitCommand getUpdateCommand();
 
     /** {@inheritDoc} */
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/test/java/org/apache/maven/scm/provider/git/TestGitScmProvider.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/test/java/org/apache/maven/scm/provider/git/TestGitScmProvider.java
index 3f07e9a..7e701d3 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/test/java/org/apache/maven/scm/provider/git/TestGitScmProvider.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/test/java/org/apache/maven/scm/provider/git/TestGitScmProvider.java
@@ -76,6 +76,10 @@ public class TestGitScmProvider
         return null;
     }
 
+    protected GitCommand getUntagCommand() {
+        return null;
+    }
+
     protected GitCommand getUpdateCommand()
     {
         return null;
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/GitExeScmProvider.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/GitExeScmProvider.java
index 2096cad..478667d 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/GitExeScmProvider.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/GitExeScmProvider.java
@@ -38,6 +38,7 @@ import org.apache.maven.scm.provider.git.gitexe.command.remoteinfo.GitRemoteInfo
 import org.apache.maven.scm.provider.git.gitexe.command.remove.GitRemoveCommand;
 import org.apache.maven.scm.provider.git.gitexe.command.status.GitStatusCommand;
 import org.apache.maven.scm.provider.git.gitexe.command.tag.GitTagCommand;
+import org.apache.maven.scm.provider.git.gitexe.command.untag.GitUntagCommand;
 import org.apache.maven.scm.provider.git.gitexe.command.update.GitUpdateCommand;
 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
 import org.apache.maven.scm.repository.ScmRepositoryException;
@@ -110,6 +111,10 @@ public class GitExeScmProvider
         return new GitTagCommand();
     }
 
+    @Override protected GitCommand getUntagCommand() {
+        return new GitUntagCommand();
+    }
+
     /** {@inheritDoc} */
     protected GitCommand getUpdateCommand()
     {
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/untag/GitUntagCommand.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/untag/GitUntagCommand.java
new file mode 100644
index 0000000..89c6acc
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/untag/GitUntagCommand.java
@@ -0,0 +1,120 @@
+package org.apache.maven.scm.provider.git.gitexe.command.untag;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.maven.scm.ScmException;
+import org.apache.maven.scm.ScmFileSet;
+import org.apache.maven.scm.ScmFileStatus;
+import org.apache.maven.scm.ScmResult;
+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.AbstractUntagCommand;
+import org.apache.maven.scm.command.untag.UntagScmResult;
+import org.apache.maven.scm.provider.ScmProviderRepository;
+import org.apache.maven.scm.provider.git.command.GitCommand;
+import org.apache.maven.scm.provider.git.gitexe.command.GitCommandLineUtils;
+import org.apache.maven.scm.provider.git.gitexe.command.list.GitListCommand;
+import org.apache.maven.scm.provider.git.gitexe.command.list.GitListConsumer;
+import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.cli.CommandLineUtils;
+import org.codehaus.plexus.util.cli.Commandline;
+
+/**
+ * @author <a href="https://pr0methean.github.io">Chris Hennick</a>
+ *
+ */
+public class GitUntagCommand
+    extends AbstractUntagCommand
+    implements GitCommand
+{
+    
+    /** {@inheritDoc} */
+    public ScmResult executeUntagCommand( ScmProviderRepository repo, ScmFileSet fileSet, String tag )
+        throws ScmException
+    {
+        if ( tag == null || StringUtils.isEmpty( tag.trim() ) )
+        {
+            throw new ScmException( "tag name must be specified" );
+        }
+
+        GitScmProviderRepository repository = (GitScmProviderRepository) repo;
+
+        CommandLineUtils.StringStreamConsumer stdout = new CommandLineUtils.StringStreamConsumer();
+        CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
+
+        int exitCode;
+
+        Commandline clTag = createCommandLine( repository, fileSet.getBasedir(), tag );
+
+        exitCode = GitCommandLineUtils.execute( clTag, stdout, stderr, getLogger() );
+        if ( exitCode != 0 )
+        {
+            return new UntagScmResult( clTag.toString(), "The git-tag command failed.", stderr.getOutput(), false );
+        }
+
+        if ( repo.isPushChanges() )
+        {
+            // and now push the tag to the configured upstream repository
+            Commandline clPush = createPushCommandLine( repository, fileSet, tag );
+
+            exitCode = GitCommandLineUtils.execute( clPush, stdout, stderr, getLogger() );
+            if ( exitCode != 0 )
+            {
+                return new UntagScmResult( clPush.toString(), "The git-push command failed.", stderr.getOutput(),
+                                         false );
+            }
+        }
+
+        return new UntagScmResult( clTag.toString() );
+
+
+    }
+
+    // ----------------------------------------------------------------------
+    //
+    // ----------------------------------------------------------------------
+
+    public static Commandline createCommandLine( GitScmProviderRepository repository, File workingDirectory,
+                                                 String tag )
+    {
+        Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory, "tag" );
+
+        cl.createArg().setValue( "-d" );
+        cl.createArg().setValue( tag );
+
+        return cl;
+    }
+
+    public static Commandline createPushCommandLine( GitScmProviderRepository repository, ScmFileSet fileSet,
+                                                     String tag ) {
+        Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( fileSet.getBasedir(), "push" );
+        cl.createArg().setValue( "--delete" );
+        cl.createArg().setValue( repository.getPushUrl() );
+        cl.createArg().setValue( "refs/tags/" + tag );
+
+        return cl;
+    }
+
+}
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/JGitScmProvider.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/JGitScmProvider.java
index b155dea..1a01a9d 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/JGitScmProvider.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/JGitScmProvider.java
@@ -39,6 +39,7 @@ import org.apache.maven.scm.provider.git.jgit.command.list.JGitListCommand;
 import org.apache.maven.scm.provider.git.jgit.command.remoteinfo.JGitRemoteInfoCommand;
 import org.apache.maven.scm.provider.git.jgit.command.status.JGitStatusCommand;
 import org.apache.maven.scm.provider.git.jgit.command.tag.JGitTagCommand;
+import org.apache.maven.scm.provider.git.jgit.command.untag.JGitUntagCommand;
 import org.apache.maven.scm.repository.ScmRepositoryException;
 
 /**
@@ -133,6 +134,13 @@ public class JGitScmProvider
     /**
      * {@inheritDoc}
      */
+    protected GitCommand getUntagCommand() {
+        return new JGitUntagCommand();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     protected GitCommand getUpdateCommand()
     {
         throw new UnsupportedOperationException( "getUpdateCommand" );
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
new file mode 100644
index 0000000..f376c35
--- /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/untag/JGitUntagCommand.java
@@ -0,0 +1,61 @@
+package org.apache.maven.scm.provider.git.jgit.command.untag;
+
+import org.apache.maven.scm.ScmException;
+import org.apache.maven.scm.ScmFileSet;
+import org.apache.maven.scm.ScmResult;
+import org.apache.maven.scm.command.untag.AbstractUntagCommand;
+import org.apache.maven.scm.command.untag.UntagScmResult;
+import org.apache.maven.scm.provider.ScmProviderRepository;
+import org.apache.maven.scm.provider.git.command.GitCommand;
+import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
+import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
+import org.codehaus.plexus.util.StringUtils;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.transport.RefSpec;
+
+/**
+ * @author <a href="https://pr0methean.github.io">Chris Hennick</a>
+ *
+ */
+public class JGitUntagCommand extends AbstractUntagCommand implements GitCommand {
+
+    @Override
+    protected ScmResult executeUntagCommand(ScmProviderRepository repository, ScmFileSet fileSet,
+        String tagName) throws ScmException
+    {
+        if ( tagName == null || StringUtils.isEmpty( tagName.trim() ) )
+        {
+            throw new ScmException( "tag name must be specified" );
+        }
+        String escapedTagName = tagName.trim().replace( ' ', '_' );
+
+        Git git = null;
+        try
+        {
+            git = JGitUtils.openRepo( fileSet.getBasedir() );
+
+            // delete the tag
+            if (git.tagDelete().setTags( escapedTagName ).call().isEmpty()) {
+                return new UntagScmResult("JGit tagDelete", "Failed to delete tag", "", false);
+            }
+
+            if ( repository.isPushChanges() )
+            {
+                getLogger().info( "push delete tag [" + escapedTagName + "] to remote..." );
+                JGitUtils.push( getLogger(), git, (GitScmProviderRepository) repository, new RefSpec( Constants.R_TAGS
+                    + escapedTagName ) );
+            }
+
+            return new UntagScmResult( "JGit tagDelete" );
+        }
+        catch ( Exception e )
+        {
+            throw new ScmException( "JGit tagDelete failure!", e );
+        }
+        finally
+        {
+            JGitUtils.closeRepo( git );
+        }
+    }
+}
diff --git a/maven-scm-providers/maven-scm-providers-svn/maven-scm-provider-svn-commons/pom.xml b/maven-scm-providers/maven-scm-providers-svn/maven-scm-provider-svn-commons/pom.xml
index 8c9f472..87bc9a2 100644
--- a/maven-scm-providers/maven-scm-providers-svn/maven-scm-provider-svn-commons/pom.xml
+++ b/maven-scm-providers/maven-scm-providers-svn/maven-scm-provider-svn-commons/pom.xml
@@ -21,6 +21,13 @@
 
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven.scm</groupId>
+      <artifactId>maven-scm-provider-svn-commons</artifactId>
+      <version>1.9.4</version>
+    </dependency>
+  </dependencies>
 
   <parent>
     <groupId>org.apache.maven.scm</groupId>