From d0f73ba31947fdd08ed9ff5cd34209721fb6f2f9 Mon Sep 17 00:00:00 2001 From: zilmTT Date: Mon, 24 Aug 2015 12:28:44 +0200 Subject: [PATCH 1/3] Fix wrong condition in getPathContents() If the deletion and adding path share some characters the contains() function succeed and removes the added path. It should be checked if they are equal. This fixes some rename issues we discovered in our environment. --- .../hudson/plugins/scm_sync_configuration/model/ChangeSet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/hudson/plugins/scm_sync_configuration/model/ChangeSet.java b/src/main/java/hudson/plugins/scm_sync_configuration/model/ChangeSet.java index 9b39f18c..48081baa 100644 --- a/src/main/java/hudson/plugins/scm_sync_configuration/model/ChangeSet.java +++ b/src/main/java/hudson/plugins/scm_sync_configuration/model/ChangeSet.java @@ -82,7 +82,7 @@ public Map getPathContents(){ for(Path pathToAdd : filteredPathContents.keySet()){ for(Path pathToDelete : pathsToDelete){ // Removing paths being both in pathsToDelete and pathContents - if(pathToDelete.contains(pathToAdd)){ + if(pathToDelete.equals(pathToAdd)){ filteredPaths.add(pathToAdd); } } From c1ff378ed3f37b0d205378562417b64e99e9998f Mon Sep 17 00:00:00 2001 From: zilmTT Date: Mon, 24 Aug 2015 12:32:41 +0200 Subject: [PATCH 2/3] Fix hierarchy deletion issues (JENKINS-26652) Before deleting the job hierarchy it is needed to check for changes on the files, e.g config.xml. While deleting a job it gets updated, this blocks the git -rm command from deleting this hierarchy. Commits should always come with proper messages, git command fails if the commit message is empty. Which put scm-sync in an dirty state if there are commits which cannot be pushed. --- .../SCMManipulator.java | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) 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 279cbfcb..bd396718 100644 --- a/src/main/java/hudson/plugins/scm_sync_configuration/SCMManipulator.java +++ b/src/main/java/hudson/plugins/scm_sync_configuration/SCMManipulator.java @@ -2,6 +2,16 @@ import hudson.plugins.scm_sync_configuration.model.ScmContext; import hudson.plugins.scm_sync_configuration.scms.SCM; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + import org.apache.maven.scm.ScmException; import org.apache.maven.scm.ScmFile; import org.apache.maven.scm.ScmFileSet; @@ -9,20 +19,12 @@ import org.apache.maven.scm.command.checkin.CheckInScmResult; import org.apache.maven.scm.command.checkout.CheckOutScmResult; import org.apache.maven.scm.command.remove.RemoveScmResult; +import org.apache.maven.scm.command.status.StatusScmResult; import org.apache.maven.scm.command.update.UpdateScmResult; import org.apache.maven.scm.manager.NoSuchScmProviderException; import org.apache.maven.scm.manager.ScmManager; import org.apache.maven.scm.repository.ScmRepository; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - /** * Class providing atomic scm commands and wrapping calls to maven scm api * with logging informations @@ -123,7 +125,17 @@ public List deleteHierarchy(File hierarchyToDelete){ try { ScmFileSet deleteFileSet = new ScmFileSet(enclosingDirectory, hierarchyToDelete); - RemoveScmResult removeResult = this.scmManager.remove(this.scmRepository, deleteFileSet, ""); + StatusScmResult checkForChanges = this.scmManager.status(scmRepository, deleteFileSet); + LOGGER.fine("Checking for changes on SCM hierarchy ["+hierarchyToDelete.getAbsolutePath()+"] from SCM ..."); + for (ScmFile changedFile : checkForChanges.getChangedFiles()) { + //check in this change as it affect our hierarchy + LOGGER.fine("[checkForChanges] Found changed file "+changedFile.toString()+", try to check-in..."); + CheckInScmResult checkedInChangedFile = scmManager.checkIn(scmRepository, new ScmFileSet(enclosingDirectory.getParentFile(), new File(changedFile.getPath())), "Check-In changes for "+changedFile.getPath()); + if(!checkedInChangedFile.isSuccess()){ + LOGGER.severe("[checkForChanges] Failed to check-in changed file ["+changedFile.getPath()+"]: "+checkedInChangedFile.getProviderMessage()); + } + } + RemoveScmResult removeResult = this.scmManager.remove(this.scmRepository, deleteFileSet, "Delete hierarchy "+hierarchyToDelete.getPath()); if(!removeResult.isSuccess()){ LOGGER.severe("[deleteHierarchy] Problem during remove : "+removeResult.getProviderMessage()); return null; From 2eb8f2635b01df5e351244c76fe3531a40f638eb Mon Sep 17 00:00:00 2001 From: zilmTT Date: Mon, 24 Aug 2015 12:34:14 +0200 Subject: [PATCH 3/3] Add a basic filter for FileUtil.copy As i encountered some copy issues, e.g was not able to copy blank build/ dir, i implemented a basic filter for the FileUtil.copy function. This matches on any XML-File and on includes specified on ManualIncludes list from scm-sync-configuration. --- .../ScmSyncConfigurationBusiness.java | 28 +++++++++++++++++-- .../ScmSyncConfigurationPlugin.java | 3 ++ 2 files changed, 28 insertions(+), 3 deletions(-) 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 8e43be65..682bfe0b 100644 --- a/src/main/java/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationBusiness.java +++ b/src/main/java/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationBusiness.java @@ -1,6 +1,7 @@ package hudson.plugins.scm_sync_configuration; import com.google.common.io.Files; + import hudson.model.Hudson; import hudson.model.User; import hudson.plugins.scm_sync_configuration.exceptions.LoggableException; @@ -9,6 +10,7 @@ import hudson.plugins.scm_sync_configuration.utils.Checksums; import hudson.security.Permission; import hudson.util.DaemonThreadFactory; + import org.apache.commons.io.FileUtils; import org.apache.maven.scm.ScmException; import org.apache.maven.scm.manager.ScmManager; @@ -36,6 +38,7 @@ public class ScmSyncConfigurationBusiness { private SCMManipulator scmManipulator; private File checkoutScmDirectory = null; private ScmSyncConfigurationStatusManager scmSyncConfigurationStatusManager = null; + private List manualSynchronizationIncludes = new ArrayList(); /** * Use of a size 1 thread pool frees us from worrying about accidental thread death and @@ -172,8 +175,17 @@ private void processCommitsQueue() { String firstNonExistingParentScmPath = pathRelativeToJenkinsRoot.getFirstNonExistingParentScmPath(); try { - FileUtils.copyDirectory(JenkinsFilesHelper.buildFileFromPathRelativeToHudsonRoot(pathRelativeToJenkinsRoot.getPath()), - fileTranslatedInScm); + File buildFileFromPathRelativeToHudsonRoot = JenkinsFilesHelper.buildFileFromPathRelativeToHudsonRoot(pathRelativeToJenkinsRoot.getPath()); + FileUtils.copyDirectory(buildFileFromPathRelativeToHudsonRoot, fileTranslatedInScm, new FileFilter() { + @Override + public boolean accept(File pathname) { + if(pathname.getPath().endsWith(".xml") + || getManualSynchronizationIncludes().contains(pathname)){ + return true; + } + return false; + } + }); } catch (IOException e) { throw new LoggableException("Error while copying file hierarchy to SCM checkouted directory", FileUtils.class, "copyDirectory", e); } @@ -197,7 +209,8 @@ private void processCommitsQueue() { } for(Path path : commit.getChangeset().getPathsToDelete()){ List deletedFiles = deleteHierarchy(commit.getScmContext(), path); - updatedFiles.addAll(deletedFiles); + if(deletedFiles != null) + updatedFiles.addAll(deletedFiles); } if(updatedFiles.isEmpty()){ @@ -228,6 +241,15 @@ private void processCommitsQueue() { } } + public List getManualSynchronizationIncludes() { + return manualSynchronizationIncludes; + } + + public void setManualSynchronizationIncludes( + List manualSynchronizationIncludes) { + this.manualSynchronizationIncludes = manualSynchronizationIncludes; + } + private boolean writeScmContentOnlyIfItDiffers(Path pathRelativeToJenkinsRoot, byte[] content, File fileTranslatedInScm) throws LoggableException { boolean scmContentUpdated = false; diff --git a/src/main/java/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin.java b/src/main/java/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin.java index 95b9ed11..085ecaf7 100644 --- a/src/main/java/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin.java +++ b/src/main/java/hudson/plugins/scm_sync_configuration/ScmSyncConfigurationPlugin.java @@ -145,6 +145,7 @@ public void loadData(ScmSyncConfigurationPOJO pojo){ this.displayStatus = pojo.isDisplayStatus(); this.commitMessagePattern = pojo.getCommitMessagePattern(); this.manualSynchronizationIncludes = pojo.getManualSynchronizationIncludes(); + this.business.setManualSynchronizationIncludes(manualSynchronizationIncludes); } public void init() { @@ -200,6 +201,8 @@ public void configure(StaplerRequest req, JSONObject formData) } else { this.manualSynchronizationIncludes = new ArrayList(); } + + this.business.setManualSynchronizationIncludes(manualSynchronizationIncludes); // Repo initialization should be made _before_ plugin save, in order to let scm-sync-configuration.xml // file synchronizable