Skip to content
Permalink
Browse files

[FIXED JENKINS-753] Allows performing a clean checkout if update fails

[FIXED JENKINS-12595] CVS gets passed the module name so creates lock
files in the correct directory on the remote server
[FIXED JENKINS-12581] CVS plugin now forces a module name in the udpate
command to prevent an attempt to checkout all remote modules
  • Loading branch information...
mc1arke committed Feb 5, 2012
1 parent 39da798 commit 794afd76127191e6a5174647d0c2620f0aadd915
Showing with 106 additions and 56 deletions.
  1. +103 −56 src/main/java/hudson/scm/CVSSCM.java
  2. +3 −0 src/main/resources/hudson/scm/CVSSCM/config.jelly
@@ -126,6 +126,8 @@
private boolean pruneEmptyDirectories; private boolean pruneEmptyDirectories;


private boolean disableCvsQuiet; private boolean disableCvsQuiet;

private boolean cleanOnFailedUpdate;


// start legacy fields // start legacy fields
@Deprecated @Deprecated
@@ -153,19 +155,21 @@ public CVSSCM(final String cvsRoot, final String allModules, final String branch
final boolean canUseUpdate, final boolean useHeadIfNotFound, final boolean legacy, final boolean canUseUpdate, final boolean useHeadIfNotFound, final boolean legacy,
final boolean isTag, final String excludedRegions) { final boolean isTag, final String excludedRegions) {
this(LegacyConvertor.getInstance().convertLegacyConfigToRepositoryStructure(cvsRoot, allModules, branch, isTag, excludedRegions, this(LegacyConvertor.getInstance().convertLegacyConfigToRepositoryStructure(cvsRoot, allModules, branch, isTag, excludedRegions,
useHeadIfNotFound), canUseUpdate, legacy, null, Boolean.getBoolean(CVSSCM.class.getName() + ".skipChangeLog"), true, false); useHeadIfNotFound), canUseUpdate, legacy, null, Boolean.getBoolean(CVSSCM.class.getName() + ".skipChangeLog"), true, false, false);
} }


@DataBoundConstructor @DataBoundConstructor
public CVSSCM(final List<CvsRepository> repositories, final boolean canUseUpdate, final boolean legacy, public CVSSCM(final List<CvsRepository> repositories, final boolean canUseUpdate, final boolean legacy,
final CVSRepositoryBrowser browser, final boolean skipChangeLog, final boolean pruneEmptyDirectories, final boolean disableCvsQuiet) { final CVSRepositoryBrowser browser, final boolean skipChangeLog, final boolean pruneEmptyDirectories,
final boolean disableCvsQuiet, final boolean cleanOnFailedUpdate) {
this.repositories = repositories.toArray(new CvsRepository[repositories.size()]); this.repositories = repositories.toArray(new CvsRepository[repositories.size()]);
this.canUseUpdate = canUseUpdate; this.canUseUpdate = canUseUpdate;
this.skipChangeLog = skipChangeLog; this.skipChangeLog = skipChangeLog;
flatten = !legacy && this.repositories.length == 1 && this.repositories[0].getModules().length == 1 && "".equals(fixNull(this.repositories[0].getModules()[0].getLocalName())); flatten = !legacy && this.repositories.length == 1 && this.repositories[0].getModules().length == 1 && "".equals(fixNull(this.repositories[0].getModules()[0].getLocalName()));
repositoryBrowser = browser; repositoryBrowser = browser;
this.pruneEmptyDirectories = pruneEmptyDirectories; this.pruneEmptyDirectories = pruneEmptyDirectories;
this.disableCvsQuiet = disableCvsQuiet; this.disableCvsQuiet = disableCvsQuiet;
this.cleanOnFailedUpdate = cleanOnFailedUpdate;
} }




@@ -645,6 +649,11 @@ public boolean isFlatten() {
public boolean isDisableCvsQuiet() { public boolean isDisableCvsQuiet() {
return disableCvsQuiet; return disableCvsQuiet;
} }

@Exported
public boolean isCleanOnFailedUpdate() {
return cleanOnFailedUpdate;
}


public boolean isLegacy() { public boolean isLegacy() {
return !flatten; return !flatten;
@@ -705,11 +714,7 @@ public boolean checkout(final AbstractBuild<?, ?> build, final Launcher launcher


final FilePath module = workspace.child(cvsModule.getCheckoutName()); final FilePath module = workspace.child(cvsModule.getCheckoutName());


final Client cvsClient = getCvsClient(repository, envVars); boolean updateFailed = false;
final GlobalOptions globalOptions = getGlobalOptions(repository, envVars);

final Command cvsCommand;

boolean update = false; boolean update = false;


if (flatten) { if (flatten) {
@@ -721,7 +726,13 @@ public boolean checkout(final AbstractBuild<?, ?> build, final Launcher launcher
update = true; update = true;
} }
} }

final FilePath targetWorkspace = flatten ? workspace.getParent() : workspace;


final String moduleName= flatten ?workspace.getName() : cvsModule.getCheckoutName();


// we're doing an update
if (update) { if (update) {
// we're doing a CVS update // we're doing a CVS update
UpdateCommand updateCommand = new UpdateCommand(); UpdateCommand updateCommand = new UpdateCommand();
@@ -748,9 +759,22 @@ public boolean checkout(final AbstractBuild<?, ?> build, final Launcher launcher
updateCommand.setUpdateByRevision(CvsModuleLocationType.HEAD.getName().toUpperCase()); updateCommand.setUpdateByRevision(CvsModuleLocationType.HEAD.getName().toUpperCase());
updateCommand.setUpdateByDate(dateStamp); updateCommand.setUpdateByDate(dateStamp);
} }

if (!perform(updateCommand, targetWorkspace, listener, repository, moduleName, envVars)) {
updateFailed = true;
}


cvsCommand = updateCommand; }
} else {

// we're doing a checkout
if (!update || (updateFailed && cleanOnFailedUpdate)) {

if (updateFailed) {
listener.getLogger().println("Update failed. Cleaning workspace and performing full checkout");
workspace.deleteContents();
}

// we're doing a CVS checkout // we're doing a CVS checkout
CheckoutCommand checkoutCommand = new CheckoutCommand(); CheckoutCommand checkoutCommand = new CheckoutCommand();


@@ -774,58 +798,16 @@ public boolean checkout(final AbstractBuild<?, ?> build, final Launcher launcher
// set directory pruning // set directory pruning
checkoutCommand.setPruneDirectories(isPruneEmptyDirectories()); checkoutCommand.setPruneDirectories(isPruneEmptyDirectories());


// tell it what to checkout the module as - if we're // set where we're checking out to
// flattening then we ignore any user set name checkoutCommand.setCheckoutDirectory(moduleName);
if (flatten) {
checkoutCommand.setCheckoutDirectory(workspace.getName());
} else {
checkoutCommand.setCheckoutDirectory(cvsModule.getCheckoutName());
}


// and specify which module to load // and specify which module to load
checkoutCommand.setModule(cvsModule.getRemoteName()); checkoutCommand.setModule(cvsModule.getRemoteName());


cvsCommand = checkoutCommand; if (!perform(checkoutCommand, workspace, listener, repository, moduleName, envVars)) {

return false;
}

listener.getLogger().println("cvs " + cvsCommand.getCVSCommand());

final FilePath targetWorkspace = flatten ? workspace.getParent() : update ? workspace.child(cvsModule
.getCheckoutName()) : workspace;

if (!targetWorkspace.act(new FileCallable<Boolean>() {

private static final long serialVersionUID = -7517978923721181408L;

@Override
public Boolean invoke(final File workspace, final VirtualChannel channel) throws RuntimeException {
cvsClient.setLocalPath(workspace.getAbsolutePath());
final BasicListener basicListener = new BasicListener(listener.getLogger(), listener.getLogger());
cvsClient.getEventManager().addCVSListener(basicListener);

try {
return cvsClient.executeCommand(cvsCommand, globalOptions);
} catch (CommandAbortedException e) {
e.printStackTrace(listener.error("CVS Command aborted: " + e.getMessage()));
return false;
} catch (CommandException e) {
e.printStackTrace(listener.error("CVS Command failed: " + e.getMessage()));
return false;
} catch (AuthenticationException e) {
e.printStackTrace(listener.error("CVS Authentication failed: " + e.getMessage()));
return false;
} finally {
try {
cvsClient.getConnection().close();
} catch(IOException ex) {
listener.error("Could not close client connection: " + ex.getMessage());
}
}
} }
})) {
listener.error("Cvs task failed");
return false;
} }


} }
@@ -870,6 +852,71 @@ public Void invoke(final File f, final VirtualChannel channel) throws IOExceptio


return true; return true;
} }

/**
* Runs a cvs command in the given workspace.
* @param cvsCommand the command to run (checkout, update etc)
* @param workspace the workspace to run the command in
* @param listener where to log output to
* @param repository the repository to connect to
* @param moduleName the name of the directory within the workspace that will have work performed on it
* @param envVars the environmental variables to expand
* @return true if the action succeeds, false otherwise
* @throws IOException on failure handling files or server actions
* @throws InterruptedException if the user cancels the action
*/
private boolean perform(final Command cvsCommand, final FilePath workspace, final TaskListener listener,
final CvsRepository repository, final String moduleName, final EnvVars envVars) throws IOException, InterruptedException {

final Client cvsClient = getCvsClient(repository, envVars);
final GlobalOptions globalOptions = getGlobalOptions(repository, envVars);


if (!workspace.act(new FileCallable<Boolean>() {

private static final long serialVersionUID = -7517978923721181408L;

@Override
public Boolean invoke(final File workspace, final VirtualChannel channel) throws RuntimeException {


if (cvsCommand instanceof UpdateCommand) {
((UpdateCommand) cvsCommand).setFiles(new File[]{new File(workspace, moduleName)});
}

listener.getLogger().println("cvs " + cvsCommand.getCVSCommand());


cvsClient.setLocalPath(workspace.getAbsolutePath());
final BasicListener basicListener = new BasicListener(listener.getLogger(), listener.getLogger());
cvsClient.getEventManager().addCVSListener(basicListener);

try {
return cvsClient.executeCommand(cvsCommand, globalOptions);
} catch (CommandAbortedException e) {
e.printStackTrace(listener.error("CVS Command aborted: " + e.getMessage()));
return false;
} catch (CommandException e) {
e.printStackTrace(listener.error("CVS Command failed: " + e.getMessage()));
return false;
} catch (AuthenticationException e) {
e.printStackTrace(listener.error("CVS Authentication failed: " + e.getMessage()));
return false;
} finally {
try {
cvsClient.getConnection().close();
} catch(IOException ex) {
listener.error("Could not close client connection: " + ex.getMessage());
}
}
}
})) {
listener.error("Cvs task failed");
return false;
}

return true;
}


private Map<CvsRepository, List<CvsFile>> calculateWorkspaceState(final FilePath workspace) throws IOException, private Map<CvsRepository, List<CvsFile>> calculateWorkspaceState(final FilePath workspace) throws IOException,
InterruptedException { InterruptedException {
@@ -42,5 +42,8 @@ THE SOFTWARE.
<f:entry title="${%Show all CVS output}" field="disableCvsQuiet"> <f:entry title="${%Show all CVS output}" field="disableCvsQuiet">
<f:checkbox /> <f:checkbox />
</f:entry> </f:entry>
<f:entry title="${%Perform clean checkout on failed update}" field="cleanOnFailedUpdate">
<f:checkbox />
</f:entry>
<t:listScmBrowsers name="cvs.browser" /> <t:listScmBrowsers name="cvs.browser" />
</j:jelly> </j:jelly>

0 comments on commit 794afd7

Please sign in to comment.
You can’t perform that action at this time.