diff --git a/pom.xml b/pom.xml
index 54c7ef89..e0fc945e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -145,7 +145,8 @@
org.jenkins-ci.pluginssubversion1.39
-
+
+
com.google.code.maven-scm-provider-svnjava
@@ -159,6 +160,11 @@
1.6
+
+ org.apache.maven.scm
+ maven-scm-provider-hg
+ 1.8
+
diff --git a/src/main/java/hudson/plugins/scm_sync_configuration/SCMManipulator.java b/src/main/java/hudson/plugins/scm_sync_configuration/SCMManipulator.java
index f2af3515..b15ba70f 100644
--- a/src/main/java/hudson/plugins/scm_sync_configuration/SCMManipulator.java
+++ b/src/main/java/hudson/plugins/scm_sync_configuration/SCMManipulator.java
@@ -106,14 +106,16 @@ public boolean checkout(File checkoutDirectory){
return checkoutOk;
}
- public List deleteHierarchy(File hierarchyToDelete){
+ public List deleteHierarchy(File hierarchyToDelete, String hierarchyPath){
if(!expectScmRepositoryInitiated()){
return null;
}
- File enclosingDirectory = hierarchyToDelete.getParentFile();
-
- LOGGER.fine("Deleting SCM hierarchy ["+hierarchyToDelete.getAbsolutePath()+"] from SCM ...");
+ String absolutePath = hierarchyToDelete.getAbsolutePath();
+ String basePath = absolutePath.substring(0, absolutePath.lastIndexOf(hierarchyPath));
+ File enclosingDirectory = new File(basePath);
+
+ LOGGER.fine("Deleting SCM hierarchy ["+absolutePath+"] from SCM ...");
File commitFile = hierarchyToDelete;
while(! commitFile.isDirectory()) {
diff --git a/src/main/java/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationBusiness.java b/src/main/java/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationBusiness.java
index a4112e7f..eda658e6 100644
--- a/src/main/java/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationBusiness.java
+++ b/src/main/java/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationBusiness.java
@@ -110,7 +110,7 @@ public List deleteHierarchy(ScmContext scmContext, Path hierarchyPath){
File rootHierarchyTranslatedInScm = hierarchyPath.getScmFile();
- List filesToCommit = scmManipulator.deleteHierarchy(rootHierarchyTranslatedInScm);
+ List filesToCommit = scmManipulator.deleteHierarchy(rootHierarchyTranslatedInScm, hierarchyPath.getPath());
// Once done, we should delete path in scm if it is a directory
if(hierarchyPath.isDirectory()){
diff --git a/src/main/java/hudson/plugins/scm_sync_configuration/scms/SCM.java b/src/main/java/hudson/plugins/scm_sync_configuration/scms/SCM.java
index f473948d..722de775 100644
--- a/src/main/java/hudson/plugins/scm_sync_configuration/scms/SCM.java
+++ b/src/main/java/hudson/plugins/scm_sync_configuration/scms/SCM.java
@@ -25,6 +25,7 @@ public abstract class SCM {
add(new ScmSyncNoSCM());
add(new ScmSyncSubversionSCM());
add(new ScmSyncGitSCM());
+ add(new ScmSyncHgSCM());
} };
transient protected String title;
diff --git a/src/main/java/hudson/plugins/scm_sync_configuration/scms/ScmSyncHgSCM.java b/src/main/java/hudson/plugins/scm_sync_configuration/scms/ScmSyncHgSCM.java
new file mode 100644
index 00000000..1de33a4b
--- /dev/null
+++ b/src/main/java/hudson/plugins/scm_sync_configuration/scms/ScmSyncHgSCM.java
@@ -0,0 +1,31 @@
+package hudson.plugins.scm_sync_configuration.scms;
+
+import org.kohsuke.stapler.StaplerRequest;
+
+public class ScmSyncHgSCM extends SCM {
+
+ private static final String SCM_URL_PREFIX="scm:hg:";
+
+ ScmSyncHgSCM(){
+ super("Mercurial", "hg/config.jelly", "hudson.plugins.mercurial.MercurialSCM", "/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/url-help.jelly");
+ }
+
+ public String createScmUrlFromRequest(StaplerRequest req) {
+ String repoURL = req.getParameter("hgRepositoryUrl");
+ if(repoURL == null){
+ return null;
+ }
+ else {
+ return SCM_URL_PREFIX+repoURL;
+ }
+ }
+
+ public String extractScmUrlFrom(String scmUrl) {
+ return scmUrl.substring(SCM_URL_PREFIX.length());
+ }
+
+ public SCMCredentialConfiguration extractScmCredentials(String scmUrl) {
+ return null;
+ }
+
+}
diff --git a/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/config.jelly b/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/config.jelly
new file mode 100644
index 00000000..e089d694
--- /dev/null
+++ b/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/config.jelly
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/config_fr.properties b/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/config_fr.properties
new file mode 100644
index 00000000..7c14cc25
--- /dev/null
+++ b/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/config_fr.properties
@@ -0,0 +1 @@
+Repository\ URL=URL du repository
diff --git a/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/url-help.jelly b/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/url-help.jelly
new file mode 100644
index 00000000..e5c23d37
--- /dev/null
+++ b/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/url-help.jelly
@@ -0,0 +1,32 @@
+
+
+
+
+
+ ${%description.1}
+ ${%description.2}
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/url-help.properties b/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/url-help.properties
new file mode 100644
index 00000000..8c1247f1
--- /dev/null
+++ b/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/url-help.properties
@@ -0,0 +1,26 @@
+# The MIT License
+#
+# Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+description.1=\
+ Specify the hg repository URL to synchronize your configuration files with, such as "hg@bitbucket.org:mycompany/jenkins-config"
+description.2=\
+ Note that, for the moment, your MUST reference your Hg repository root
diff --git a/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/url-help_fr.properties b/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/url-help_fr.properties
new file mode 100644
index 00000000..d90cd208
--- /dev/null
+++ b/src/main/resources/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin/scms/hg/url-help_fr.properties
@@ -0,0 +1,26 @@
+# The MIT License
+#
+# Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Eric Lefevre-Ardant
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+description.1=\
+ Spécifier l''url du repository Hg vers lequel synchroniser vos fichiers de configuration, tel que "hg@bitbucket.org/mycompany/jenkins-config"
+description.2=\
+ A noter qu''il est pour le moment obligatoire de référencer la racine du repository
diff --git a/src/test/java/hudson/plugins/scm_sync_configuration/repository/HudsonExtensionsHgTest.java b/src/test/java/hudson/plugins/scm_sync_configuration/repository/HudsonExtensionsHgTest.java
new file mode 100644
index 00000000..b6cdab06
--- /dev/null
+++ b/src/test/java/hudson/plugins/scm_sync_configuration/repository/HudsonExtensionsHgTest.java
@@ -0,0 +1,16 @@
+package hudson.plugins.scm_sync_configuration.repository;
+
+import hudson.plugins.test.utils.scms.ScmUnderTestHg;
+import org.junit.Ignore;
+
+public class HudsonExtensionsHgTest extends HudsonExtensionsTest {
+
+ public HudsonExtensionsHgTest() {
+ super(new ScmUnderTestHg());
+ }
+
+ @Ignore("Should be re-activated once maven-scm-api 1.9 is released (see JENKINS-15128)")
+ public void shouldJobRenameBeCorrectlyImpactedOnSCM() throws Throwable {
+ super.shouldJobRenameBeCorrectlyImpactedOnSCM();
+ }
+}
diff --git a/src/test/java/hudson/plugins/scm_sync_configuration/repository/HudsonExtensionsTest.java b/src/test/java/hudson/plugins/scm_sync_configuration/repository/HudsonExtensionsTest.java
index 67bb10e0..ec86139b 100644
--- a/src/test/java/hudson/plugins/scm_sync_configuration/repository/HudsonExtensionsTest.java
+++ b/src/test/java/hudson/plugins/scm_sync_configuration/repository/HudsonExtensionsTest.java
@@ -294,7 +294,7 @@ public void shouldReloadAllFilesUpdateScmAndReloadAllFiles() throws Throwable {
final File configJobFile = new File(checkoutDirectoryForVerifications.getAbsolutePath() + "/jobs/fakeJob/config.xml");
FileUtils.fileAppend(configJobFile.getAbsolutePath(), "titi");
- scmManipulator.checkinFiles(checkoutDirectoryForVerifications, "external commit on jonb file");
+ scmManipulator.checkinFiles(checkoutDirectoryForVerifications, "external commit on job file");
verifyCurrentScmContentMatchesCurrentHudsonDir(false);
@@ -303,6 +303,7 @@ public void shouldReloadAllFilesUpdateScmAndReloadAllFiles() throws Throwable {
verifyCurrentScmContentMatchesCurrentHudsonDir(true);
+ assertAndRemoveHgSpecificFile(syncedFiles);
assertThat(syncedFiles.size(), is(2));
assertThat(syncedFiles.contains(new File(getCurrentHudsonRootDirectory().getAbsolutePath() + "/config.xml")), is(true));
assertThat(syncedFiles.contains(new File(getCurrentHudsonRootDirectory().getAbsolutePath() + "/jobs/fakeJob/config.xml")), is(true));
@@ -345,6 +346,7 @@ public void shouldReloadAllFilesUpdateScmAndReloadAllFilesWithFileAdd() throws T
verifyCurrentScmContentMatchesCurrentHudsonDir(true);
+ assertAndRemoveHgSpecificFile(syncedFiles);
assertThat(syncedFiles.size(), is(2));
assertThat(syncedFiles.contains(new File(getCurrentHudsonRootDirectory().getAbsolutePath() + "/myConfigFile.xml")), is(true));
assertThat(syncedFiles.contains(new File(getCurrentHudsonRootDirectory().getAbsolutePath() + "/jobs/myJob")), is(true));
@@ -378,4 +380,13 @@ private void assertStrategy(Class extends ScmSyncStrategy> expectedStrategyCla
}
}
+ private void assertAndRemoveHgSpecificFile(List syncedFiles) {
+ // HG Support: If we encounter the dummy file used to initialise HG repo then we know
+ // we are dealing with a HG repo, so remove it so other tests can pass.
+ if(this instanceof HudsonExtensionsHgTest) {
+ File file = new File(getCurrentHudsonRootDirectory().getAbsolutePath() + "/hg_dummy.txt");
+ assertThat(syncedFiles.contains(file), is(true));
+ syncedFiles.remove(syncedFiles.indexOf(file));
+ }
+ }
}
diff --git a/src/test/java/hudson/plugins/scm_sync_configuration/repository/InitRepositoryHgTest.java b/src/test/java/hudson/plugins/scm_sync_configuration/repository/InitRepositoryHgTest.java
new file mode 100644
index 00000000..174b865a
--- /dev/null
+++ b/src/test/java/hudson/plugins/scm_sync_configuration/repository/InitRepositoryHgTest.java
@@ -0,0 +1,13 @@
+package hudson.plugins.scm_sync_configuration.repository;
+
+import hudson.plugins.test.utils.scms.ScmUnderTestHg;
+
+
+
+public class InitRepositoryHgTest extends InitRepositoryTest {
+
+ public InitRepositoryHgTest() {
+ super(new ScmUnderTestHg());
+ }
+
+}
diff --git a/src/test/java/hudson/plugins/scm_sync_configuration/repository/InitRepositoryTest.java b/src/test/java/hudson/plugins/scm_sync_configuration/repository/InitRepositoryTest.java
index 75107891..cb6b20bf 100644
--- a/src/test/java/hudson/plugins/scm_sync_configuration/repository/InitRepositoryTest.java
+++ b/src/test/java/hudson/plugins/scm_sync_configuration/repository/InitRepositoryTest.java
@@ -60,7 +60,14 @@ public void shouldResetCheckoutConfigurationDirectoryWhenAsked() throws Throwabl
// Reseting the repository, without cleanup
sscBusiness.initializeRepository(scmContext, false);
- assertThat(fileWhichShouldBeDeletedAfterReset.exists(), is(true));
+ if (this instanceof InitRepositoryHgTest) {
+ // HG Support: HG behaves differently and always destroys files that aren't yet in source control.
+ // Note: Should this be allowed in the first place? If a reset is requested why should it
+ // allow untracked files to linger around?
+ assertThat(fileWhichShouldBeDeletedAfterReset.exists(), is(false));
+ } else {
+ assertThat(fileWhichShouldBeDeletedAfterReset.exists(), is(true));
+ }
// Reseting the repository with cleanup
sscBusiness.initializeRepository(scmContext, true);
diff --git a/src/test/java/hudson/plugins/scm_sync_configuration/util/ScmSyncConfigurationBaseTest.java b/src/test/java/hudson/plugins/scm_sync_configuration/util/ScmSyncConfigurationBaseTest.java
index 5de847fa..5f053715 100644
--- a/src/test/java/hudson/plugins/scm_sync_configuration/util/ScmSyncConfigurationBaseTest.java
+++ b/src/test/java/hudson/plugins/scm_sync_configuration/util/ScmSyncConfigurationBaseTest.java
@@ -203,6 +203,8 @@ protected static List getSpecialSCMDirectoryExcludePattern(){
return new ArrayList(){{
add(Pattern.compile("\\.svn"));
add(Pattern.compile("\\.git.*"));
+ add(Pattern.compile("\\.hg.*"));
+ add(Pattern.compile("hg_dummy.txt"));
add(Pattern.compile("scm-sync-configuration\\..*\\.log"));
add(Pattern.compile("scm-sync-configuration"));
}};
diff --git a/src/test/java/hudson/plugins/test/utils/scms/ScmUnderTestHg.java b/src/test/java/hudson/plugins/test/utils/scms/ScmUnderTestHg.java
new file mode 100644
index 00000000..689281de
--- /dev/null
+++ b/src/test/java/hudson/plugins/test/utils/scms/ScmUnderTestHg.java
@@ -0,0 +1,51 @@
+package hudson.plugins.test.utils.scms;
+
+import hudson.plugins.scm_sync_configuration.scms.SCM;
+import hudson.plugins.scm_sync_configuration.scms.ScmSyncHgSCM;
+
+import java.io.File;
+
+import org.codehaus.plexus.util.FileUtils;
+
+public class ScmUnderTestHg implements ScmUnderTest {
+
+ public void initRepo(File path) throws Exception {
+ // HG support: Unlike Git, Mercurial does not appear to support "bare" repositories.
+ // So we have to initialise the repository by committing a dummy file.
+
+ final String dummyFileName = "hg_dummy.txt";
+ File dummyFile = new File(path, dummyFileName);
+ FileUtils.fileWrite(dummyFile.getAbsolutePath(), "This is a dummy file");
+
+ ProcessBuilder[] commands = new ProcessBuilder[] {
+ new ProcessBuilder("hg", "init"),
+ new ProcessBuilder("hg", "add", dummyFileName),
+ new ProcessBuilder("hg", "commit", "-m", "\"initial commit\"")
+ };
+
+ for (ProcessBuilder pb : commands) {
+ pb.directory(path);
+ Process p = pb.start();
+ if (p.waitFor() != 0) {
+ throw new Exception("Unable to init hg repo in " + path.getAbsolutePath());
+ }
+ }
+ }
+
+ public String createUrl(String url) {
+ return "scm:hg:" + url;
+ }
+
+ public Class extends SCM> getClazz() {
+ return ScmSyncHgSCM.class;
+ }
+
+ public boolean useCredentials() {
+ return false;
+ }
+
+ public String getSuffixForTestFiles() {
+ return ".hg";
+ }
+
+}
diff --git a/src/test/resources/expected-scm-hierarchies/HudsonExtensionsTest.shouldJobDeleteBeCorrectlyImpactedOnSCM.hg/config.xml b/src/test/resources/expected-scm-hierarchies/HudsonExtensionsTest.shouldJobDeleteBeCorrectlyImpactedOnSCM.hg/config.xml
new file mode 100644
index 00000000..824eae41
--- /dev/null
+++ b/src/test/resources/expected-scm-hierarchies/HudsonExtensionsTest.shouldJobDeleteBeCorrectlyImpactedOnSCM.hg/config.xml
@@ -0,0 +1,31 @@
+
+
+ 1.339
+ 2
+ NORMAL
+ true
+
+
+ true
+
+ Welcome !
+
+
+
+ 5
+ 0
+
+
+
+ All
+ false
+ false
+
+
+ All
+ 0
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/expected-scm-hierarchies/HudsonExtensionsTest.shouldJobDeleteBeCorrectlyImpactedOnSCM.hg/hudson.tasks.Shell.xml b/src/test/resources/expected-scm-hierarchies/HudsonExtensionsTest.shouldJobDeleteBeCorrectlyImpactedOnSCM.hg/hudson.tasks.Shell.xml
new file mode 100644
index 00000000..8b953697
--- /dev/null
+++ b/src/test/resources/expected-scm-hierarchies/HudsonExtensionsTest.shouldJobDeleteBeCorrectlyImpactedOnSCM.hg/hudson.tasks.Shell.xml
@@ -0,0 +1,5 @@
+
+
+
+ /bin/bash
+
\ No newline at end of file
diff --git a/src/test/resources/expected-scm-hierarchies/HudsonExtensionsTest.shouldJobDeleteBeCorrectlyImpactedOnSCM.hg/scm-sync-configuration.xml b/src/test/resources/expected-scm-hierarchies/HudsonExtensionsTest.shouldJobDeleteBeCorrectlyImpactedOnSCM.hg/scm-sync-configuration.xml
new file mode 100644
index 00000000..a83018f2
--- /dev/null
+++ b/src/test/resources/expected-scm-hierarchies/HudsonExtensionsTest.shouldJobDeleteBeCorrectlyImpactedOnSCM.hg/scm-sync-configuration.xml
@@ -0,0 +1,5 @@
+
+
+ scm:svn:https://myrepo/synchronizedDirectory/
+
+
\ No newline at end of file