Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JENKINS-19659: Support for disabling default sync strategies. #58

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
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;
Expand Down Expand Up @@ -124,7 +125,17 @@ public List<File> 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class ScmSyncConfigurationBusiness {
private SCMManipulator scmManipulator;
private File checkoutScmDirectory = null;
private ScmSyncConfigurationStatusManager scmSyncConfigurationStatusManager = null;
private List<String> manualSynchronizationIncludes = new ArrayList<String>();

/**
* Use of a size 1 thread pool frees us from worrying about accidental thread death and
Expand Down Expand Up @@ -187,8 +188,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 directory", FileUtils.class, "copyDirectory", e);
}
Expand All @@ -212,7 +222,9 @@ private void processCommitsQueue() {
}
for(Path path : commit.getChangeset().getPathsToDelete()){
List<File> deletedFiles = deleteHierarchy(commit.getScmContext(), path);
updatedFiles.addAll(deletedFiles);
if(deletedFiles != null) {
updatedFiles.addAll(deletedFiles);
}
}

if(updatedFiles.isEmpty()){
Expand Down Expand Up @@ -245,6 +257,14 @@ private void processCommitsQueue() {
}
}

public List<String> getManualSynchronizationIncludes() {
return manualSynchronizationIncludes;
}
public void setManualSynchronizationIncludes(
List<String> manualSynchronizationIncludes) {
this.manualSynchronizationIncludes = manualSynchronizationIncludes;
}

private boolean writeScmContentOnlyIfItDiffers(Path pathRelativeToJenkinsRoot, byte[] content, File fileTranslatedInScm)
throws LoggableException {
boolean scmContentUpdated = false;
Expand Down Expand Up @@ -295,10 +315,10 @@ private void createScmContent(Path pathRelativeToJenkinsRoot, byte[] content, Fi
}
}

public void synchronizeAllConfigs(ScmSyncStrategy[] availableStrategies){
public void synchronizeAllConfigs(List<ScmSyncStrategy> enabledStrategies){
List<File> filesToSync = new ArrayList<File>();
// Building synced files from strategies
for(ScmSyncStrategy strategy : availableStrategies){
for(ScmSyncStrategy strategy : enabledStrategies){
filesToSync.addAll(strategy.collect());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

import hudson.Plugin;
import hudson.model.Descriptor;
Expand Down Expand Up @@ -60,18 +59,37 @@

public class ScmSyncConfigurationPlugin extends Plugin{

public static final transient ScmSyncStrategy[] AVAILABLE_STRATEGIES = new ScmSyncStrategy[]{
private static final transient ScmSyncStrategy[] AVAILABLE_STRATEGIES = new ScmSyncStrategy[]{
new JenkinsConfigScmSyncStrategy(),
new BasicPluginsConfigScmSyncStrategy(),
new JobConfigScmSyncStrategy(),
new UserConfigScmSyncStrategy(),
new ManualIncludesScmSyncStrategy()
};


private List<ScmSyncStrategy> enabledStrategies = new ArrayList<ScmSyncStrategy>();

private void setEnabledStrategies() {
enabledStrategies.clear();
for (ScmSyncStrategy strategy : AVAILABLE_STRATEGIES) {
if ( (strategy instanceof JenkinsConfigScmSyncStrategy && syncJenkinsConfig) ||
(strategy instanceof BasicPluginsConfigScmSyncStrategy && syncBasicPluginsConfig) ||
(strategy instanceof JobConfigScmSyncStrategy && syncJobConfig) ||
(strategy instanceof UserConfigScmSyncStrategy && syncUserConfig) ||
(strategy instanceof ManualIncludesScmSyncStrategy) ) {
enabledStrategies.add(strategy);
}
}
}

public List<ScmSyncStrategy> getEnabledStrategies() {
return enabledStrategies;
}

/**
* Strategies that cannot be updated by user
*/
public static final transient List<ScmSyncStrategy> DEFAULT_STRATEGIES = ImmutableList.copyOf(
private static final transient List<ScmSyncStrategy> DEFAULT_STRATEGIES = ImmutableList.copyOf(
Collections2.filter(Arrays.asList(AVAILABLE_STRATEGIES), new Predicate<ScmSyncStrategy>() {
@Override
public boolean apply(@Nullable ScmSyncStrategy scmSyncStrategy) {
Expand Down Expand Up @@ -109,6 +127,11 @@ public static interface AtomicTransactionFactory {
private SCM scm;
private boolean noUserCommitMessage;
private boolean displayStatus = true;
private boolean syncJenkinsConfig = true;
private boolean syncBasicPluginsConfig = true;
private boolean syncJobConfig = true;
private boolean syncUserConfig = true;

// The [message] is a magic string that will be replaced with commit message
// when commit occurs
private String commitMessagePattern = "[message]";
Expand Down Expand Up @@ -162,8 +185,14 @@ public void loadData(ScmSyncConfigurationPOJO pojo){
this.scm = pojo.getScm();
this.noUserCommitMessage = pojo.isNoUserCommitMessage();
this.displayStatus = pojo.isDisplayStatus();
this.syncJenkinsConfig = pojo.isSyncJenkinsConfig();
this.syncBasicPluginsConfig = pojo.isSyncBasicPluginsConfig();
this.syncJobConfig = pojo.isSyncJobConfig();
this.syncUserConfig = pojo.isSyncUserConfig();
this.commitMessagePattern = pojo.getCommitMessagePattern();
this.manualSynchronizationIncludes = pojo.getManualSynchronizationIncludes();
this.business.setManualSynchronizationIncludes(manualSynchronizationIncludes);
this.setEnabledStrategies();
}

protected void initialInit() throws Exception {
Expand Down Expand Up @@ -199,6 +228,10 @@ public void configure(StaplerRequest req, JSONObject formData)

this.noUserCommitMessage = formData.getBoolean("noUserCommitMessage");
this.displayStatus = formData.getBoolean("displayStatus");
this.syncJenkinsConfig = formData.getBoolean("syncJenkinsConfig");
this.syncBasicPluginsConfig = formData.getBoolean("syncBasicPluginsConfig");
this.syncJobConfig = formData.getBoolean("syncJobConfig");
this.syncUserConfig = formData.getBoolean("syncUserConfig");
this.commitMessagePattern = req.getParameter("commitMessagePattern");

String oldScmRepositoryUrl = this.scmRepositoryUrl;
Expand All @@ -223,18 +256,28 @@ public void configure(StaplerRequest req, JSONObject formData)
}
this.manualSynchronizationIncludes = submittedManualIncludes;

configsResynchronizationRequired = !newManualIncludes.isEmpty();
configsResynchronizationRequired = configsResynchronizationRequired || !newManualIncludes.isEmpty();
} else {
this.manualSynchronizationIncludes = new ArrayList<String>();
}

this.business.setManualSynchronizationIncludes(manualSynchronizationIncludes);

// Load strategies and check whether they should be reloaded
List<ScmSyncStrategy> currentEnabledStrategies = new ArrayList<ScmSyncStrategy>(this.enabledStrategies);
this.setEnabledStrategies();
if (currentEnabledStrategies.size() < this.enabledStrategies.size()) {
currentEnabledStrategies.removeAll(this.enabledStrategies);
configsResynchronizationRequired = configsResynchronizationRequired || currentEnabledStrategies.isEmpty();
}

// Repo initialization should be made _before_ plugin save, in order to let scm-sync-configuration.xml
// file synchronizable
if(repoInitializationRequired){
this.business.initializeRepository(createScmContext(), true);
}
if(configsResynchronizationRequired){
this.business.synchronizeAllConfigs(AVAILABLE_STRATEGIES);
this.business.synchronizeAllConfigs(this.enabledStrategies);
}
if(repoCleaningRequired){
this.business.cleanChekoutScmDirectory();
Expand All @@ -247,15 +290,15 @@ public void configure(StaplerRequest req, JSONObject formData)
}

public Iterable<File> collectAllFilesForScm() {
return Iterables.concat(Iterables.transform(Lists.newArrayList(AVAILABLE_STRATEGIES), new Function<ScmSyncStrategy, Iterable<File>>() {
return Iterables.concat(Iterables.transform(enabledStrategies, new Function<ScmSyncStrategy, Iterable<File>>() {
@Override
public Iterable<File> apply(ScmSyncStrategy strategy) {
return strategy.collect();
}}));
}

public Iterable<File> collectAllFilesForScm(final File fromSubDirectory) {
return Iterables.concat(Iterables.transform(Lists.newArrayList(AVAILABLE_STRATEGIES), new Function<ScmSyncStrategy, Iterable<File>>() {
return Iterables.concat(Iterables.transform(enabledStrategies, new Function<ScmSyncStrategy, Iterable<File>>() {
@Override
public Iterable<File> apply(ScmSyncStrategy strategy) {
return strategy.collect(fromSubDirectory);
Expand Down Expand Up @@ -332,7 +375,7 @@ public static ScmSyncConfigurationPlugin getInstance(){
}

public ScmSyncStrategy getStrategyForSaveable(Saveable s, File f){
for(ScmSyncStrategy strat : AVAILABLE_STRATEGIES){
for(ScmSyncStrategy strat : enabledStrategies){
if(strat.isSaveableApplicable(s, f)){
return strat;
}
Expand All @@ -350,7 +393,7 @@ public ScmSyncStrategy getStrategyForSaveable(Saveable s, File f){
* @return a strategy that thinks it might have applied
*/
public ScmSyncStrategy getStrategyForDeletedSaveable(Saveable s, String pathRelativeToRoot, boolean wasDirectory) {
for (ScmSyncStrategy strategy : AVAILABLE_STRATEGIES) {
for (ScmSyncStrategy strategy : enabledStrategies) {
if (strategy.mightHaveBeenApplicableToDeletedSaveable(s, pathRelativeToRoot, wasDirectory)) {
return strategy;
}
Expand All @@ -376,7 +419,7 @@ public boolean shouldDecorationOccursOnURL(String url){
}

public ScmSyncStrategy getStrategyForURL(String url){
for(ScmSyncStrategy strat : AVAILABLE_STRATEGIES){
for(ScmSyncStrategy strat : enabledStrategies){
if(strat.isCurrentUrlApplicable(url)){
return strat;
}
Expand Down Expand Up @@ -429,6 +472,22 @@ public boolean isDisplayStatus() {
return displayStatus;
}

public boolean isSyncJenkinsConfig() {
return syncJenkinsConfig;
}

public boolean isSyncBasicPluginsConfig() {
return syncBasicPluginsConfig;
}

public boolean isSyncJobConfig() {
return syncJobConfig;
}

public boolean isSyncUserConfig() {
return syncUserConfig;
}

public String getCommitMessagePattern() {
return commitMessagePattern;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ public void registerPath(String path) {
public void registerPathForDeletion(String path){
// We should determine if path is a directory by watching scm path (and not hudson path) because in most of time,
// when we are here, directory is already deleted in hudson hierarchy...
boolean isDirectory = new Path(path).getScmFile().isDirectory();
pathsToDelete.add(new Path(path, isDirectory));
if(new Path(path).getScmFile().exists()) {
boolean isDirectory = new Path(path).getScmFile().isDirectory();
pathsToDelete.add(new Path(path, isDirectory));
}
}

public boolean isEmpty(){
Expand All @@ -75,7 +77,7 @@ public Map<Path, byte[]> 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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ public String[] matchingFilesFrom(File rootDirectory, FileSelector selector) {
FileSelector combinedSelector = new FileSelector() {
@Override
public boolean isSelected(File basedir, String pathRelativeToBaseDir, File file) throws BuildException {
// Make paths match the defined patterns on Windows
pathRelativeToBaseDir = pathRelativeToBaseDir.replace('\\', '/');

if (originalSelector != null && !originalSelector.isSelected(basedir, pathRelativeToBaseDir, file)) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,23 @@ public void marshal(Object source, HierarchicalStreamWriter writer,
writer.startNode(AbstractMigrator.SCM_DISPLAY_STATUS);
writer.setValue(Boolean.toString(plugin.isDisplayStatus()));
writer.endNode();

writer.startNode(AbstractMigrator.SCM_SYNC_JENKINS_CONFIG);
writer.setValue(Boolean.toString(plugin.isSyncJenkinsConfig()));
writer.endNode();

writer.startNode(AbstractMigrator.SCM_SYNC_PLUGINS_CONFIG);
writer.setValue(Boolean.toString(plugin.isSyncBasicPluginsConfig()));
writer.endNode();

writer.startNode(AbstractMigrator.SCM_SYNC_JOB_CONFIG);
writer.setValue(Boolean.toString(plugin.isSyncJobConfig()));
writer.endNode();

writer.startNode(AbstractMigrator.SCM_SYNC_USER_DATA);
writer.setValue(Boolean.toString(plugin.isSyncUserConfig()));
writer.endNode();

if(plugin.getCommitMessagePattern() != null){
writer.startNode(AbstractMigrator.SCM_COMMIT_MESSAGE_PATTERN);
writer.setValue(plugin.getCommitMessagePattern());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ public abstract class AbstractMigrator<TFROM extends ScmSyncConfigurationPOJO, T
public static final String SCM_CLASS_ATTRIBUTE = "class";
public static final String SCM_NO_USER_COMMIT_MESSAGE = "noUserCommitMessage";
public static final String SCM_DISPLAY_STATUS = "displayStatus";
public static final String SCM_SYNC_JENKINS_CONFIG = "syncJenkinsConfig";
public static final String SCM_SYNC_PLUGINS_CONFIG = "syncBasicPluginsConfig";
public static final String SCM_SYNC_JOB_CONFIG = "syncJobConfig";
public static final String SCM_SYNC_USER_DATA = "syncUserConfig";
public static final String SCM_COMMIT_MESSAGE_PATTERN = "commitMessagePattern";
public static final String SCM_MANUAL_INCLUDES = "manualSynchronizationIncludes";

Expand All @@ -40,6 +44,10 @@ public TTO readScmSyncConfigurationPOJO(
String scmContent = null;
boolean noUserCommitMessage = false;
boolean displayStatus = true;
boolean syncJenkinsConfig = true;
boolean syncBasicPluginsConfig = true;
boolean syncJobConfig = true;
boolean syncUserConfig = true;
String commitMessagePattern = "[message]";
List<String> manualIncludes = null;

Expand All @@ -51,6 +59,14 @@ public TTO readScmSyncConfigurationPOJO(
noUserCommitMessage = Boolean.parseBoolean(reader.getValue());
} else if(SCM_DISPLAY_STATUS.equals(reader.getNodeName())){
displayStatus = Boolean.parseBoolean(reader.getValue());
} else if(SCM_SYNC_JENKINS_CONFIG.equals(reader.getNodeName())){
syncJenkinsConfig = Boolean.parseBoolean(reader.getValue());
} else if(SCM_SYNC_PLUGINS_CONFIG.equals(reader.getNodeName())){
syncBasicPluginsConfig = Boolean.parseBoolean(reader.getValue());
} else if(SCM_SYNC_JOB_CONFIG.equals(reader.getNodeName())){
syncJobConfig = Boolean.parseBoolean(reader.getValue());
} else if(SCM_SYNC_USER_DATA.equals(reader.getNodeName())){
syncUserConfig = Boolean.parseBoolean(reader.getValue());
} else if(SCM_TAG.equals(reader.getNodeName())){
scmClassAttribute = reader.getAttribute(SCM_CLASS_ATTRIBUTE);
scmContent = reader.getValue();
Expand All @@ -76,6 +92,10 @@ public TTO readScmSyncConfigurationPOJO(
pojo.setScmRepositoryUrl(scmRepositoryUrl);
pojo.setNoUserCommitMessage(noUserCommitMessage);
pojo.setDisplayStatus(displayStatus);
pojo.setSyncJenkinsConfig(syncJenkinsConfig);
pojo.setSyncBasicPluginsConfig(syncBasicPluginsConfig);
pojo.setSyncJobConfig(syncJobConfig);
pojo.setSyncUserConfig(syncUserConfig);
pojo.setCommitMessagePattern(commitMessagePattern);
pojo.setManualSynchronizationIncludes(manualIncludes);

Expand Down
Loading