nskvortsov avatar nskvortsov committed c370821 Merge with conflicts

Merge branch 'dev' into dev_7.1

Conflicts:
deploy-runner/build.gradle

Comments (0)

Files changed (38)

deploy-runner/build.gradle

 
 
 
-
 ext.teamCityVersion = '7.1.1'
-
+ext.pluginVersion = new Date().format("yyyyMMddHHmmss");
 
 
 apply from: 'https://raw.github.com/evgeny-goldin/gradle-plugins/master/teamcity/teamcity.gradle'
     vendorUrl   'Plugin vendor URL'
     vendorLogo  'Plugin vendor logo URL'
 
-    version     "snapshot-${new Date().format("yyyyMMddHHmmss")}"
+    version     "snapshot-${pluginVersion}"
 
     server      project( ':deploy-runner-server' )
     agent       project( ':deploy-runner-agent'  )
 project( ':deploy-runner-agent' ) {
 
     configurations {
+        providedCompile
         compile { extendsFrom teamcityAgentEx }
         testCompile { extendsFrom teamcityTest }
     }
 
     dependencies {
+        providedCompile 'org.apache.ant:ant:1.8.2',
+                'log4j:log4j:1.2.12'
+
         compile project(":deploy-runner-common"),
                 files("lib/ftp4j-1.7.2.jar"),
                 'org.samba.jcifs:jcifs:1.3.17',
-                'com.jcraft:jsch:0.1.47',
-                'org.apache.ant:ant:1.8.2',
-                'log4j:log4j:1.2.17',
-
+                'com.jcraft:jsch:0.1.47'
                 compile("org.apache.tomcat:tomcat-catalina-ant:7.0.0") {
                     transitive = false
                 }
 
     }
 
+    sourceSets {
+        main {
+            compileClasspath += configurations.providedCompile
+        }
+    }
+
     test {
         useTestNG()
     }

deploy-runner/deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/ftp/FtpBuildProcessAdapter.java

 import jetbrains.buildServer.RunBuildException;
 import jetbrains.buildServer.agent.BuildFinishedStatus;
 import jetbrains.buildServer.agent.BuildProcessAdapter;
+import jetbrains.buildServer.agent.BuildProgressLogger;
+import jetbrains.buildServer.agent.BuildRunnerContext;
 import jetbrains.buildServer.agent.impl.artifacts.ArtifactsCollection;
 import jetbrains.buildServer.log.Loggers;
 import jetbrains.buildServer.util.StringUtil;
 
 
 class FtpBuildProcessAdapter extends BuildProcessAdapter {
+    private static final String FTP_PROTOCOL = "ftp://";
 
     private final String myTarget;
     private final String myUsername;
     private final String myPassword;
     private final List<ArtifactsCollection> myArtifacts;
-    private static final String FTP_PROTOCOL = "ftp://";
+    private final BuildProgressLogger myLogger;
 
     private volatile boolean hasFinished;
 
-    public FtpBuildProcessAdapter(@NotNull final String target,
+    public FtpBuildProcessAdapter(@NotNull final BuildRunnerContext context,
+                                  @NotNull final String target,
                                   @NotNull final String username,
                                   @NotNull final String password,
                                   @NotNull final List<ArtifactsCollection> artifactsCollections) {
         myUsername = username;
         myPassword = password;
         myArtifacts = artifactsCollections;
+        myLogger = context.getBuild().getBuildLogger();
         hasFinished = false;
     }
 
 
             final String remoteRoot = client.currentDirectory();
 
+            myLogger.message("Starting upload via FTP to " + myTarget);
+
             for (ArtifactsCollection artifactsCollection : myArtifacts) {
+                int count = 0;
                 for (Map.Entry<File, String> fileStringEntry : artifactsCollection.getFilePathMap().entrySet()) {
                     final File source = fileStringEntry.getKey();
                     final String destinationDir = fileStringEntry.getValue();
                     client.changeDirectory(destinationDir);
                     client.upload(source);
                     client.changeDirectory(remoteRoot);
+                    count++;
                 }
+                myLogger.message("Uploaded [" + count + "] files for [" + artifactsCollection.getSourcePath() + "] pattern");
             }
 
 
         final String normalisedPath = path.trim().replaceAll("\\\\","/");
         final StringTokenizer pathTokenizer = new StringTokenizer(normalisedPath, "/");
         final StringBuilder sb = new StringBuilder(pathTokenizer.nextToken());
-        client.createDirectory(sb.toString());
+        createDirSkipExisting(client, sb.toString());
         while(pathTokenizer.hasMoreTokens()) {
             sb.append('/').append(pathTokenizer.nextToken());
-            client.createDirectory(sb.toString());
+            createDirSkipExisting(client, sb.toString());
+        }
+    }
+
+    private void createDirSkipExisting(FTPClient client, final String directoryName) throws IOException, FTPIllegalReplyException, FTPException {
+        try {
+            client.createDirectory(directoryName);
+        } catch (FTPException e) {
+            // we can safely ignore if dir already exists
+            if (!e.getMessage().contains("already exists")) {
+                throw e;
+            }
         }
     }
 }

deploy-runner/deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/ftp/FtpDeployerRunner.java

                                               @NotNull final String password,
                                               @NotNull final String target,
                                               @NotNull final List<ArtifactsCollection> artifactsCollections) {
-        return new FtpBuildProcessAdapter(target, username, password, artifactsCollections);
+        return new FtpBuildProcessAdapter(context, target, username, password, artifactsCollections);
     }
 
     @NotNull

deploy-runner/deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/smb/SMBBuildProcessAdapter.java

 import jetbrains.buildServer.RunBuildException;
 import jetbrains.buildServer.agent.BuildFinishedStatus;
 import jetbrains.buildServer.agent.BuildProcessAdapter;
+import jetbrains.buildServer.agent.BuildProgressLogger;
+import jetbrains.buildServer.agent.BuildRunnerContext;
 import jetbrains.buildServer.agent.impl.artifacts.ArtifactsCollection;
 import jetbrains.buildServer.log.Loggers;
 import jetbrains.buildServer.util.FileUtil;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.io.File;
 import java.io.FileInputStream;
 class SMBBuildProcessAdapter extends BuildProcessAdapter {
     public static final String SMB = "smb://";
 
-
-    private volatile boolean hasFinished;
     private final String myTarget;
     private final String myUsername;
     private final String myPassword;
     private final List<ArtifactsCollection> myArtifactsCollections;
+    private final String myDomain;
+    private final BuildProgressLogger myLogger;
 
-    public SMBBuildProcessAdapter(@NotNull final String username,
+    private volatile boolean hasFinished;
+
+    public SMBBuildProcessAdapter(@NotNull final BuildRunnerContext context,
+                                  @NotNull final String username,
                                   @NotNull final String password,
+                                  @Nullable final String domain,
                                   @NotNull final String target,
                                   @NotNull final List<ArtifactsCollection> artifactsCollections) {
         myTarget = target;
         myUsername = username;
         myPassword = password;
+        myDomain = domain;
         myArtifactsCollections = artifactsCollections;
+        myLogger = context.getBuild().getBuildLogger();
         hasFinished = false;
     }
 
     @Override
     public void start() throws RunBuildException {
 
-        jcifs.Config.setProperty("jcifs.smb.client.disablePlainTextPasswords", "false"); // ???
+        jcifs.Config.setProperty("jcifs.smb.client.disablePlainTextPasswords", "false");
 
         String targetWithProtocol;
         if (myTarget.startsWith("\\\\")) {
 
         targetWithProtocol = targetWithProtocol.replaceAll("\\\\", "/");
 
-        NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(myUsername.split("\\\\")[0],
-                myUsername.split("\\\\")[1], myPassword);
+        NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(myDomain == null ? "" : myDomain,
+                myUsername, myPassword);
 
         final String settingsString = "Trying to connect with following parameters:\n" +
                 "username=[" + myUsername + "]\n" +
                 "password=[" + myPassword + "]\n" +
+                "domain=[" + (myDomain == null ? "" : myDomain) + "]\n" +
                 "target=[" + targetWithProtocol + "]";
         try {
             Loggers.AGENT.debug(settingsString);
+            myLogger.message("Starting upload via SMB to " + myTarget);
             SmbFile destinationDir = new SmbFile(targetWithProtocol, auth);
 
             for (ArtifactsCollection artifactsCollection : myArtifactsCollections) {
-                upload(artifactsCollection.getFilePathMap(), destinationDir);
+                final int numOfUploadedFiles = upload(artifactsCollection.getFilePathMap(), destinationDir);
+                myLogger.message("Uploaded [" + numOfUploadedFiles + "] files for [" + artifactsCollection.getSourcePath() + "] pattern");
             }
 
         } catch (Exception e) {
         }
     }
 
-    private void upload(Map<File, String> filePathMap, SmbFile destination) throws IOException {
+    private int upload(Map<File, String> filePathMap, SmbFile destination) throws IOException {
+        int count = 0;
         for (Map.Entry<File, String> fileDestEntry : filePathMap.entrySet()) {
             final File source = fileDestEntry.getKey();
             final SmbFile destDirectory = new SmbFile(destination, fileDestEntry.getValue() + "/");  // Share and directories names require trailing /
                 FileUtil.close(inputStream);
                 FileUtil.close(outputStream);
             }
+            count++;
         }
-
+        return count;
     }
 
 }

deploy-runner/deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/smb/SmbDeployerRunner.java

 import jetbrains.buildServer.agent.*;
 import jetbrains.buildServer.agent.impl.artifacts.ArtifactsCollection;
 import jetbrains.buildServer.deployer.agent.base.BaseDeployerRunner;
+import jetbrains.buildServer.deployer.common.DeployerRunnerConstants;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.List;
                                               @NotNull final String password,
                                               @NotNull final String target,
                                               @NotNull final List<ArtifactsCollection> artifactsCollections) {
-        return new SMBBuildProcessAdapter(username, password, target, artifactsCollections);
+        final String domain = context.getRunnerParameters().get(DeployerRunnerConstants.PARAM_DOMAIN);
+        return new SMBBuildProcessAdapter(context, username, password, domain, target, artifactsCollections);
     }
 
     @NotNull

deploy-runner/deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/ssh/SSHDeployerRunner.java

  */
 public class SSHDeployerRunner extends BaseDeployerRunner {
 
+
+
     public SSHDeployerRunner(@NotNull final ExtensionHolder extensionHolder) {
         super(extensionHolder);
     }
                                               @NotNull final String target,
                                               @NotNull final List<ArtifactsCollection> artifactsCollections) throws RunBuildException {
         final String transport = context.getRunnerParameters().get(SSHRunnerConstants.PARAM_TRANSPORT);
+        final String portStr = context.getRunnerParameters().get(SSHRunnerConstants.PARAM_PORT);
+        int port;
+        try {
+            port = Integer.parseInt(portStr);
+        } catch (NumberFormatException e) {
+            port = 22;
+        }
 
         if (SSHRunnerConstants.TRANSPORT_SCP.equals(transport)) {
-            return new ScpProcessAdapter(username, password, target, artifactsCollections);
+            return new ScpProcessAdapter(username, password, target, port, context, artifactsCollections);
         } else if (SSHRunnerConstants.TRANSPORT_SFTP.equals(transport)) {
-            return new SftpBuildProcessAdapter(target, username, password, context, artifactsCollections);
+            return new SftpBuildProcessAdapter(username, password, target, port, context, artifactsCollections);
         } else {
             throw new RunBuildException("Unknown ssh transport [" + transport + "]");
         }

deploy-runner/deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/ssh/SSHDeployerRunnerInfo.java

     @NotNull
     @Override
     public String getType() {
-        return DeployerRunnerConstants.SCP_RUN_TYPE;
+        return DeployerRunnerConstants.SSH_RUN_TYPE;
     }
 
     @Override

deploy-runner/deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/ssh/SSHExecProcessAdapter.java

 class SSHExecProcessAdapter extends BuildProcessAdapter {
 
     private final String myHost;
+    private final int myPort;
     private final String myUsername;
     private final String myPassword;
     private final String myCommands;
     private volatile boolean hasFinished;
 
 
+
     public SSHExecProcessAdapter(@NotNull final String host,
+                                 final int port,
                                  @NotNull final String username,
                                  @NotNull final String password,
                                  @NotNull final String commands,
                                  @NotNull final BuildProgressLogger buildLogger) {
         myHost = host;
+        myPort = port;
         myUsername = username;
         myPassword = password;
         myCommands = commands;
 
         try {
 
-            session = jsch.getSession(myUsername, myHost, 22);
+            session = jsch.getSession(myUsername, myHost, myPort);
             session.setPassword(myPassword);
             session.connect();
 

deploy-runner/deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/ssh/SSHExecRunner.java

         final String host = context.getRunnerParameters().get(SSHRunnerConstants.PARAM_HOST);
         final String command = context.getRunnerParameters().get(SSHRunnerConstants.PARAM_COMMAND);
 
-        return new SSHExecProcessAdapter(host, username, password, command, runningBuild.getBuildLogger());
+        final String portStr = context.getRunnerParameters().get(SSHRunnerConstants.PARAM_PORT);
+        int port;
+        try {
+            port = Integer.parseInt(portStr);
+        } catch (NumberFormatException e) {
+            port = 22;
+        }
+
+
+        return new SSHExecProcessAdapter(host, port, username, password, command, runningBuild.getBuildLogger());
     }
 
     @NotNull

deploy-runner/deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/ssh/scp/ScpProcessAdapter.java

 import jetbrains.buildServer.RunBuildException;
 import jetbrains.buildServer.agent.BuildFinishedStatus;
 import jetbrains.buildServer.agent.BuildProcessAdapter;
+import jetbrains.buildServer.agent.BuildProgressLogger;
+import jetbrains.buildServer.agent.BuildRunnerContext;
 import jetbrains.buildServer.agent.impl.artifacts.ArtifactsCollection;
 import jetbrains.buildServer.util.FileUtil;
 import jetbrains.buildServer.util.StringUtil;
 
     private volatile boolean hasFinished;
     private volatile boolean isInterrupted;
+    private final int myPort;
+    private final BuildProgressLogger myLogger;
 
 
     public ScpProcessAdapter(@NotNull final String username,
                              @NotNull final String password,
                              @NotNull final String target,
+                             final int port,
+                             @NotNull final BuildRunnerContext context,
                              @NotNull final List<ArtifactsCollection> artifactsCollections) {
         myTargetString = target;
         myUsername = username;
         myPassword = password;
         myArtifacts = artifactsCollections;
-
+        myPort = port;
+        myLogger = context.getBuild().getBuildLogger();
         hasFinished = false;
         isInterrupted = false;
     }
             Session session = null;
 
             try {
-                session = jsch.getSession(myUsername, host, 22);
+                session = jsch.getSession(myUsername, host, myPort);
                 session.setPassword(myPassword);
                 session.connect();
 
                 createRemotePath(session, escapedRemotePath);
                 if (isInterrupted()) return;
+                myLogger.message("Starting upload via SCP to " +
+                        (StringUtil.isNotEmpty(escapedRemotePath) ?
+                        "[" + escapedRemotePath + "] on " : "") + "host [" + host + ":" + myPort + "]");
                 upload(session, escapedRemotePath);
 
             } catch (Exception e) {
 
         try {
             for (ArtifactsCollection artifactCollection : myArtifacts) {
+                int count = 0;
                 for (Map.Entry<File, String> filePathEntry : artifactCollection.getFilePathMap().entrySet()) {
                     final File source = filePathEntry.getKey();
                     final String destination = filePathEntry.getValue();
                     final ScpOperation operationChain = ScpOperationBuilder.getCopyFileOperation(source, destination);
                     operationChain.execute(out, in);
+                    count++;
                 }
+                myLogger.message("Uploaded [" + count + "] files for [" + artifactCollection.getSourcePath() + "] pattern");
             }
         } finally {
             FileUtil.close(out);

deploy-runner/deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/ssh/sftp/SftpBuildProcessAdapter.java

 import jetbrains.buildServer.agent.BuildRunnerContext;
 import jetbrains.buildServer.agent.impl.artifacts.ArtifactsCollection;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.io.File;
 import java.util.List;
 public class SftpBuildProcessAdapter extends BuildProcessAdapter {
 
     private final String myTarget;
+    private final int myPort;
     private final String myUsername;
     private final String myPassword;
     private final List<ArtifactsCollection> myArtifacts;
 
     private volatile boolean hasFinished;
-    private BuildProgressLogger myLogger;
+    private final BuildProgressLogger myLogger;
 
-    public SftpBuildProcessAdapter(@NotNull final String target,
-                                   @NotNull final String username,
+    public SftpBuildProcessAdapter(@NotNull final String username,
                                    @NotNull final String password,
+                                   @NotNull final String target,
+                                   final int port,
                                    @NotNull final BuildRunnerContext context,
                                    @NotNull final List<ArtifactsCollection> artifactsCollections) {
         myTarget = target;
+        myPort = port;
         myUsername = username;
         myPassword = password;
         myLogger = context.getBuild().getBuildLogger();
         Session session = null;
 
         try {
-            session = jsch.getSession(myUsername, host, 22);
+            session = jsch.getSession(myUsername, host, myPort);
             session.setPassword(myPassword);
             session.connect();
 
             ChannelSftp channel = (ChannelSftp)session.openChannel("sftp");
             channel.connect();
             if (!StringUtil.isEmpty(escapedRemotePath)) {
-                myLogger.message("Creating path [" + escapedRemotePath + "]");
                 createRemotePath(channel, escapedRemotePath);
                 channel.cd(escapedRemotePath);
             }
 
+            myLogger.message("Starting upload via SFTP to " +
+                                    (jetbrains.buildServer.util.StringUtil.isNotEmpty(escapedRemotePath) ?
+                                    "[" + escapedRemotePath + "] on " : "") + "host [" + host + ":" + myPort + "]");
             for (ArtifactsCollection artifactsCollection : myArtifacts) {
+                int count = 0;
                 for (Map.Entry<File, String> fileStringEntry : artifactsCollection.getFilePathMap().entrySet()) {
                     final File source = fileStringEntry.getKey();
                     final String destinationPath = escapePathForSSH(fileStringEntry.getValue());
-
-                    myLogger.message(
-                            "Copying [" + source.getAbsolutePath() + "] to [" + destinationPath + "]"
-                    );
-                    myLogger.message("creating artifact path [" + destinationPath + "]");
                     createRemotePath(channel, destinationPath);
                     channel.put(source.getAbsolutePath(), destinationPath);
+                    count++;
                 }
-
+                myLogger.message("Uploaded [" + count + "] files for [" + artifactsCollection.getSourcePath() + "] pattern");
             }
             channel.disconnect();
 
             createRemotePath(channel, destination.substring(0, endIndex));
         }
         try {
-            myLogger.message("calling stat for [" + destination + "]");
             channel.stat(destination);
-            myLogger.message("path [" + destination + "] exists");
         } catch (SftpException e) {
             // dir does not exist.
             if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
-                myLogger.message("no_such_file caught, calling mkdir [" + destination + "]");
                 channel.mkdir(destination);
-                myLogger.message("created path [" + destination + "]");
             }
         }
 

deploy-runner/deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/tomcat/TomcatBuildProcessAdapter.java

 import jetbrains.buildServer.RunBuildException;
 import jetbrains.buildServer.agent.BuildFinishedStatus;
 import jetbrains.buildServer.agent.BuildProcessAdapter;
+import jetbrains.buildServer.agent.BuildProgressLogger;
 import jetbrains.buildServer.agent.BuildRunnerContext;
+import jetbrains.buildServer.util.StringUtil;
 import org.apache.catalina.ant.DeployTask;
+import org.apache.catalina.ant.ListTask;
+import org.apache.catalina.ant.UndeployTask;
+import org.apache.tools.ant.Project;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.io.File;
 
 
 class TomcatBuildProcessAdapter extends BuildProcessAdapter {
 
-    private static final String MANAGER_APP_SUFFIX = "manager/html";
+    private static final String MANAGER_APP_SUFFIX = "manager";
     private static final String HTTP_PREFIX = "http://";
-    private final String target;
-    private final String username;
-    private final String password;
-    private final BuildRunnerContext context;
-    private final String sourcePath;
+    private static final String CONTEXTS_LIST_PROPERTY = "temp.contexts.list";
+
+    private final String myTarget;
+    private final String myUsername;
+    private final String myPassword;
+    private final BuildProgressLogger myLogger;
 
     private volatile boolean hasFinished;
+    private final String myWepappContext;
+    private final File myWarArchive;
+
+
+    public TomcatBuildProcessAdapter(final @NotNull String target,
+                                     final @NotNull String username,
+                                     final @NotNull String password,
+                                     final @NotNull BuildRunnerContext context,
+                                     final @NotNull String sourcePath,
+                                     final @Nullable String contextPath) {
+        myTarget = target;
+        myUsername = username;
+        myPassword = password;
+        myLogger = context.getBuild().getBuildLogger();
+        myWarArchive = new File(context.getWorkingDirectory(), sourcePath);
 
-    public TomcatBuildProcessAdapter(String target, String username, String password, BuildRunnerContext context, String sourcePath) {
-        this.target = target;
-        this.username = username;
-        this.password = password;
-        this.context = context;
-        this.sourcePath = sourcePath;
+        if (contextPath == null || StringUtil.isEmptyOrSpaces(contextPath)) {
+        final String fileNameWithExtension = myWarArchive.getName();
+            // leading / is required!
+            myWepappContext = "/" + fileNameWithExtension.substring(0, fileNameWithExtension.length() - 4);
+        } else {
+            // leading / is required!
+            myWepappContext = contextPath.startsWith("/") ? contextPath : "/" + contextPath;
+        }
         hasFinished = false;
     }
 
 
         try {
             final StringBuilder sb = new StringBuilder();
-            if (!target.startsWith(HTTP_PREFIX)) {
+            if (!myTarget.startsWith(HTTP_PREFIX)) {
                 sb.append(HTTP_PREFIX);
             }
-            sb.append(target);
+            sb.append(myTarget);
 
-            if (!target.endsWith(MANAGER_APP_SUFFIX)) { // path to manager/html is required
-                if (!target.endsWith("/")) {
+            if (!myTarget.endsWith(MANAGER_APP_SUFFIX)) { // path to manager/html is required
+                if (!myTarget.endsWith("/")) {
                     sb.append('/');
                 }
                 sb.append(MANAGER_APP_SUFFIX);
             }
 
             final String targetUrl = sb.toString();
-            DeployTask deployTask = new DeployTask();
-            deployTask.setUrl(targetUrl);
-            deployTask.setUsername(username);
-            deployTask.setPassword(password);
+            myLogger.message("Using manager app located at [" + targetUrl + "]");
 
-            final File deployableWar = new File(context.getWorkingDirectory(), sourcePath);
-            deployTask.setWar(deployableWar.getCanonicalPath());
+            final Project tempProject = new Project();
+            final ListTask list = new ListTask();
+            list.setProject(tempProject);
+            list.setUrl(targetUrl);
+            list.setUsername(myUsername);
+            list.setPassword(myPassword);
+            list.setOutputproperty(CONTEXTS_LIST_PROPERTY);
+            list.execute();
 
-            final String fileNameWithExtension = deployableWar.getName();
-            final String contextName = fileNameWithExtension.substring(0, fileNameWithExtension.length() - 4);
+            final String contextsList = tempProject.getProperty(CONTEXTS_LIST_PROPERTY);
 
-            deployTask.setPath("/" + contextName);   // leading / is required!
+            if (contextsList.contains(myWepappContext)) {
+                myLogger.message("Found existing context [" + myWepappContext + "]. Trying to undeploy...");
+                final UndeployTask undeployTask = new UndeployTask();
+                undeployTask.setUrl(targetUrl);
+                undeployTask.setUsername(myUsername);
+                undeployTask.setPassword(myPassword);
+                undeployTask.setPath(myWepappContext);
+                undeployTask.execute();
+                myLogger.message("Undeployed [" + myWepappContext + "]");
+            }
+
+            myLogger.message("Deploying [" + myWarArchive.getPath() + "] to [" + myWepappContext + "]...");
+            final DeployTask deployTask = new DeployTask();
+            deployTask.setUrl(targetUrl);
+            deployTask.setUsername(myUsername);
+            deployTask.setPassword(myPassword);
+            deployTask.setWar(myWarArchive.getCanonicalPath());
+            deployTask.setPath(myWepappContext);
             deployTask.execute();
+            myLogger.message("Deployed [" + myWepappContext + "]");
+
         } catch (Exception e) {
             throw new RunBuildException(e);
         } finally {

deploy-runner/deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/tomcat/TomcatDeployerRunner.java

         final String password = context.getRunnerParameters().get(DeployerRunnerConstants.PARAM_PASSWORD);
         final String target = context.getRunnerParameters().get(DeployerRunnerConstants.PARAM_TARGET_URL);
         final String sourcePath = context.getRunnerParameters().get(DeployerRunnerConstants.PARAM_SOURCE_PATH);
+        final String contextPath = context.getRunnerParameters().get(DeployerRunnerConstants.PARAM_TOMCAT_CONTEXT_PATH);
 
-        return new TomcatBuildProcessAdapter(target, username, password, context, sourcePath);
+        return new TomcatBuildProcessAdapter(target, username, password, context, sourcePath, contextPath);
     }
 
     @NotNull

deploy-runner/deploy-runner-agent/src/test/java/jetbrains/buildServer/deployer/agent/ftp/FtpBuildProcessAdapterTest.java

 import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
 import org.apache.ftpserver.usermanager.impl.BaseUser;
 import org.apache.ftpserver.usermanager.impl.WritePermission;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.testng.Assert.assertTrue;
+
 /**
  * Created by Nikita.Skvortsov
  * Date: 10/3/12, 4:22 PM
     private final String myUsername = "myUsername";
     private final String myPassword = "myPassword";
     private List<ArtifactsCollection> myArtifactsCollections;
+    private BuildRunnerContext myContext;
 
     @BeforeMethod
     public void setUp() throws Exception {
 
         // start the server
         myServer.start();
+
+        Mockery mockeryCtx = new Mockery();
+        myContext = mockeryCtx.mock(BuildRunnerContext.class);
+        final AgentRunningBuild build = mockeryCtx.mock(AgentRunningBuild.class);
+        final BuildProgressLogger logger = new NullBuildProgressLogger();
+        final File workingDir = myTempFiles.createTempDir();
+
+        mockeryCtx.checking(new Expectations() {{
+            allowing(myContext).getWorkingDirectory(); will(returnValue(workingDir));
+            allowing(myContext).getBuild(); will(returnValue(build));
+            allowing(build).getBuildLogger(); will(returnValue(logger));
+        }});
     }
 
     @AfterMethod
         DeployTestUtils.assertCollectionsTransferred(new File(myRemoteDir, subPath), myArtifactsCollections);
     }
 
+    @Test
+    public void testTransferToExistingPath() throws Exception {
+        final String uploadDestination = "some/path";
+        final String artifactDestination = "dest1/sub";
+
+        final File existingPath = new File(myRemoteDir, uploadDestination);
+        assertTrue(existingPath.mkdirs());
+        final File existingDestination = new File(existingPath, artifactDestination);
+        assertTrue(existingDestination.mkdirs());
+
+        myArtifactsCollections.add(DeployTestUtils.buildArtifactsCollection(myTempFiles, artifactDestination, "dest2"));
+        final BuildProcess process = getProcess("127.0.0.1:" + TEST_PORT + "/" + uploadDestination);
+        DeployTestUtils.runProcess(process, 5000);
+        DeployTestUtils.assertCollectionsTransferred(existingPath, myArtifactsCollections);
+    }
+
 
     private BuildProcess getProcess(String target) {
-        return new FtpBuildProcessAdapter(target, myUsername, myPassword, myArtifactsCollections);
+        return new FtpBuildProcessAdapter(myContext, target, myUsername, myPassword, myArtifactsCollections);
     }
 }

deploy-runner/deploy-runner-agent/src/test/java/jetbrains/buildServer/deployer/agent/ssh/BaseSSHTransferTest.java

 import java.util.Arrays;
 import java.util.List;
 
+import static org.testng.Assert.assertTrue;
+
 /**
  * Created by Nikita.Skvortsov
  * Date: 10/3/12, 3:13 PM
  */
 public abstract class BaseSSHTransferTest {
 
-    private static final int PORT_NUM = 22;
+    protected static final int PORT_NUM = 15655;
 
     protected String myUsername = "testuser";
     protected final String myPassword = "testpassword";
     }
 
     @Test
-        public void testTransferAbsoluteCollectionPath() throws Exception {
+    public void testTransferAbsoluteCollectionPath() throws Exception {
         final String subPath = "test_path/subdir";
         final File tempDir1 = myTempFiles.createTempDir();
         final File tempDir2 = myTempFiles.createTempDir();
         DeployTestUtils.assertCollectionsTransferred(myRemoteDir, myArtifactsCollections);
     }
 
+    @Test
+    public void testTransferToExistingPath() throws Exception {
+        final String uploadDestination = "some/path";
+        final String artifactDestination = "dest1/sub";
+
+        final File existingPath = new File(myRemoteDir, uploadDestination);
+        assertTrue(existingPath.mkdirs());
+        final File existingDestination = new File(existingPath, artifactDestination);
+        assertTrue(existingDestination.mkdirs());
+
+        myArtifactsCollections.add(DeployTestUtils.buildArtifactsCollection(myTempFiles, artifactDestination, "dest2"));
+        final BuildProcess process = getProcess("127.0.0.1:" + uploadDestination);
+        DeployTestUtils.runProcess(process, 5000);
+        DeployTestUtils.assertCollectionsTransferred(existingPath, myArtifactsCollections);
+    }
+
+
     protected abstract BuildProcess getProcess(String targetBasePath);
 }

deploy-runner/deploy-runner-agent/src/test/java/jetbrains/buildServer/deployer/agent/ssh/scp/ScpProcessAdapterTest.java

 package jetbrains.buildServer.deployer.agent.ssh.scp;
 
 import jetbrains.buildServer.deployer.agent.ssh.BaseSSHTransferTest;
+import org.testng.annotations.Test;
 
+@Test
 public class ScpProcessAdapterTest extends BaseSSHTransferTest {
 
     @Override
     protected ScpProcessAdapter getProcess(String targetBasePath) {
-        return new ScpProcessAdapter(myUsername, myPassword, targetBasePath, myArtifactsCollections);
+        return new ScpProcessAdapter(myUsername, myPassword, targetBasePath, PORT_NUM, myContext, myArtifactsCollections);
     }
-
-
 }

deploy-runner/deploy-runner-agent/src/test/java/jetbrains/buildServer/deployer/agent/ssh/sftp/SftpProcessAdapterTest.java

 
 import jetbrains.buildServer.agent.BuildProcess;
 import jetbrains.buildServer.deployer.agent.ssh.BaseSSHTransferTest;
+import org.testng.annotations.Test;
 
+@Test
 public class SftpProcessAdapterTest extends BaseSSHTransferTest {
     @Override
     protected BuildProcess getProcess(String targetBasePath) {
-        return new SftpBuildProcessAdapter(targetBasePath, myUsername, myPassword, myContext, myArtifactsCollections);
+        return new SftpBuildProcessAdapter(myUsername, myPassword, targetBasePath, PORT_NUM, myContext, myArtifactsCollections);
     }
 }

deploy-runner/deploy-runner-common/src/main/java/jetbrains/buildServer/deployer/common/DeployerRunnerConstants.java

  * Date: 24.03.12 - 17:09
  */
 public class DeployerRunnerConstants {
-    public static final String SCP_RUN_TYPE = "scp-deploy-runner";
+    public static final String SSH_RUN_TYPE = "ssh-deploy-runner";
     public static final String SMB_RUN_TYPE = "smb-deploy-runner";
     public static final String FTP_RUN_TYPE = "ftp-deploy-runner" ;
-    public static final String SFTP_RUN_TYPE = "sftp-deploy-runner";
     public static final String TOMCAT_RUN_TYPE = "tomcat-deploy-runner";
 
 
     public static final String PARAM_USERNAME = "jetbrains.buildServer.deployer.username";
     public static final String PARAM_PASSWORD = "jetbrains.buildServer.deployer.password";
+    public static final String PARAM_DOMAIN = "jetbrains.buildServer.deployer.domain";
     public static final String PARAM_TARGET_URL = "jetbrains.buildServer.deployer.targetUrl";
     public static final String PARAM_SOURCE_PATH = "jetbrains.buildServer.deployer.sourcePath";
-    public static final String PARAM_TRANSPORT = "jetbrains.buildServer.deployer.useSftp";
+    public static final String PARAM_TOMCAT_CONTEXT_PATH = "jetbrains.buildServer.deployer.tomcat.contextPath";
 }

deploy-runner/deploy-runner-common/src/main/java/jetbrains/buildServer/deployer/common/SSHRunnerConstants.java

 package jetbrains.buildServer.deployer.common;
 
+import java.util.LinkedHashMap;
+import java.util.Map;
+
 /**
  * Created by Nikita.Skvortsov
  * Date: 9/28/12, 2:53 PM
     public static final String SSH_EXEC_RUN_TYPE = "ssh-exec-runner";
 
     public static final String PARAM_HOST = "jetbrains.buildServer.sshexec.host";
+    public static final String PARAM_PORT = "jetbrains.buildServer.sshexec.port";
     public static final String PARAM_USERNAME = "jetbrains.buildServer.sshexec.username";
     public static final String PARAM_PASSWORD = "jetbrains.buildServer.sshexec.password";
     public static final String PARAM_COMMAND = "jetbrains.buildServer.sshexec.command";
     public static final String TRANSPORT_SCP = "jetbrains.buildServer.deployer.ssh.transport.scp";
     public static final String TRANSPORT_SFTP = "jetbrains.buildServer.deployer.ssh.transport.sftp";
 
+    public String getTransportType() {
+        return PARAM_TRANSPORT;
+    }
+
+    public Map<String, String> getTransportTypeValues() {
+        final Map<String, String> result = new LinkedHashMap<String, String>();
+        result.put(TRANSPORT_SCP, "SCP");
+        result.put(TRANSPORT_SFTP, "SFTP");
+        return result;
+    }
+
+
+
 }

deploy-runner/deploy-runner-server/src/main/java/jetbrains/buildServer/deployer/server/FtpDeployerRunType.java

     public Map<String, String> getDefaultRunnerProperties() {
         return new HashMap<String, String>();
     }
+
+    @NotNull
+    @Override
+    public String describeParameters(@NotNull Map<String, String> parameters) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Target FTP server: ").append(parameters.get(DeployerRunnerConstants.PARAM_TARGET_URL));
+        return sb.toString();
+    }
 }

deploy-runner/deploy-runner-server/src/main/java/jetbrains/buildServer/deployer/server/SSHDeployerRunType.java

 package jetbrains.buildServer.deployer.server;
 
+import com.intellij.openapi.util.text.StringUtil;
+import jetbrains.buildServer.deployer.common.SSHRunnerConstants;
 import jetbrains.buildServer.serverSide.PropertiesProcessor;
 import jetbrains.buildServer.serverSide.RunType;
 import jetbrains.buildServer.serverSide.RunTypeRegistry;
     @NotNull
     @Override
     public String getType() {
-        return DeployerRunnerConstants.SCP_RUN_TYPE;
+        return DeployerRunnerConstants.SSH_RUN_TYPE;
     }
 
     @Override
     public Map<String, String> getDefaultRunnerProperties() {
         return new HashMap<String, String>();
     }
+
+    @NotNull
+    @Override
+    public String describeParameters(@NotNull Map<String, String> parameters) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Target: ").append(parameters.get(DeployerRunnerConstants.PARAM_TARGET_URL));
+        final String port = parameters.get(SSHRunnerConstants.PARAM_PORT);
+        if (StringUtil.isNotEmpty(port)) {
+            sb.append('\n').append(" Port: ").append(port);
+        }
+        final Map<String, String> transportTypeValues = new SSHRunnerConstants().getTransportTypeValues();
+        sb.append('\n').append("Protocol: ").append(transportTypeValues.get(parameters.get(SSHRunnerConstants.PARAM_TRANSPORT)));
+        return sb.toString();
+    }
 }

deploy-runner/deploy-runner-server/src/main/java/jetbrains/buildServer/deployer/server/SSHExecRunType.java

 package jetbrains.buildServer.deployer.server;
 
+import com.intellij.openapi.util.text.StringUtil;
+import jetbrains.buildServer.deployer.common.DeployerRunnerConstants;
 import jetbrains.buildServer.serverSide.PropertiesProcessor;
 import jetbrains.buildServer.serverSide.RunType;
 import jetbrains.buildServer.serverSide.RunTypeRegistry;
 import jetbrains.buildServer.deployer.common.SSHRunnerConstants;
 import org.jetbrains.annotations.NotNull;
 
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 public class SSHExecRunType extends RunType {
     public Map<String, String> getDefaultRunnerProperties() {
         return new HashMap<String, String>();
     }
+
+    @NotNull
+    @Override
+    public String describeParameters(@NotNull Map<String, String> parameters) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Target: ").append(parameters.get(SSHRunnerConstants.PARAM_HOST));
+        final String port = parameters.get(SSHRunnerConstants.PARAM_PORT);
+        if (StringUtil.isNotEmpty(port)) {
+            sb.append('\n').append(" Port: ").append(port);
+        }
+        sb.append('\n');
+        final String commands = parameters.get(SSHRunnerConstants.PARAM_COMMAND);
+        final List<String> commandsList = Arrays.asList(commands.split("\\\\n"));
+        final int size = commandsList.size();
+        if (size > 0) {
+            sb.append("Commands: ").append(commandsList.get(0));
+            if (size > 1) {
+                sb.append(" <and ").append(size - 1).append(" more line").append(size > 2 ? "s" : "").append(">");
+            }
+        } else {
+            sb.append("No commands defined.");
+        }
+        return sb.toString();
+    }
 }

deploy-runner/deploy-runner-server/src/main/java/jetbrains/buildServer/deployer/server/SmbDeployerRunType.java

     public Map<String, String> getDefaultRunnerProperties() {
         return new HashMap<String, String>();
     }
+
+    @NotNull
+    @Override
+    public String describeParameters(@NotNull Map<String, String> parameters) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Target SMB share: ").append(parameters.get(DeployerRunnerConstants.PARAM_TARGET_URL));
+        return sb.toString();
+    }
 }

deploy-runner/deploy-runner-server/src/main/java/jetbrains/buildServer/deployer/server/TomcatDeployerRunType.java

 package jetbrains.buildServer.deployer.server;
 
+import com.intellij.openapi.util.text.StringUtil;
 import jetbrains.buildServer.serverSide.PropertiesProcessor;
 import jetbrains.buildServer.serverSide.RunType;
 import jetbrains.buildServer.serverSide.RunTypeRegistry;
     public Map<String, String> getDefaultRunnerProperties() {
         return new HashMap<String, String>();
     }
+
+    @NotNull
+    @Override
+    public String describeParameters(@NotNull Map<String, String> parameters) {
+        final StringBuilder result = new StringBuilder();
+        result.append("Target Tomcat url: ").append(parameters.get(DeployerRunnerConstants.PARAM_TARGET_URL));
+        final String customContext = parameters.get(DeployerRunnerConstants.PARAM_TOMCAT_CONTEXT_PATH);
+        if (StringUtil.isNotEmpty(customContext)) {
+            result.append('\n');
+            result.append("Web app context: ").append(customContext);
+        }
+        return result.toString();
+    }
 }

deploy-runner/deploy-runner-server/src/main/resources/buildServerResources/editFtpDeployerParams.jsp

 
 <l:settingsGroup title="Deployment Target">
     <tr>
-        <th><label for="my.buildServer.deployer.targetUrl">Target host: </label></th>
+        <th><label for="jetbrains.buildServer.deployer.targetUrl">Target host: </label></th>
         <td><props:textProperty name="<%=DeployerRunnerConstants.PARAM_TARGET_URL%>"  className="longField" maxlength="256"/>
             <span class="smallNote">Enter hostname or IP address</span>
         </td>
 
 <l:settingsGroup title="Deployment Credentials">
     <tr>
-        <th><label for="my.buildServer.deployer.myUsername">Username:</label></th>
+        <th><label for="jetbrains.buildServer.deployer.username">Username:</label></th>
         <td><props:textProperty name="<%=DeployerRunnerConstants.PARAM_USERNAME%>"  className="longField" maxlength="256"/>
             <span class="smallNote">Enter username</span>
         </td>
     </tr>
     <tr>
-        <th><label for="my.buildServer.deployer.myPassword">Password:</label></th>
+        <th><label for="jetbrains.buildServer.deployer.password">Password:</label></th>
         <td><props:passwordProperty name="<%=DeployerRunnerConstants.PARAM_PASSWORD%>"  className="longField" maxlength="256"/>
             <span class="smallNote">Enter password</span>
         </td>
 
 <l:settingsGroup title="Deployment source">
     <tr>
-        <th><label for="my.buildServer.deployer.sourcePath">Artifacts path: </label></th>
+        <th><label for="jetbrains.buildServer.deployer.sourcePath">Artifacts path: </label></th>
         <td>
             <props:multilineProperty name="<%=DeployerRunnerConstants.PARAM_SOURCE_PATH%>" className="longField" cols="30" rows="4" expanded="true" linkTitle="Enter artifacts paths"/>
             <span class="smallNote">New line or comma separated paths to build artifacts. Ant-style wildcards like dir/**/*.zip and target directories like *.zip => winFiles,unix/distro.tgz => linuxFiles, where winFiles and linuxFiles are target directories are supported.</span>

deploy-runner/deploy-runner-server/src/main/resources/buildServerResources/editSSHDeployerParams.jsp

 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 <%@ taglib prefix="forms" tagdir="/WEB-INF/tags/forms" %>
 <%@ taglib prefix="bs" tagdir="/WEB-INF/tags" %>
+<jsp:useBean id="runnerConst" scope="request" class="jetbrains.buildServer.deployer.common.SSHRunnerConstants"/>
 
 <l:settingsGroup title="Deployment Target">
     <tr>
-        <th><label for="my.buildServer.deployer.targetUrl">Target: </label></th>
+        <th><label for="jetbrains.buildServer.deployer.targetUrl">Target: </label></th>
         <td><props:textProperty name="<%=DeployerRunnerConstants.PARAM_TARGET_URL%>"  className="longField" maxlength="256"/>
-            <span class="smallNote">Enter target url in form {hostname|ip_address}[:path/to/target]</span>
+            <span class="smallNote">Enter target url in form {hostname|ip_address}[:path/to/target/folder]</span>
         </td>
     </tr>
 
     <tr>
-        <th><label for="my.buildServer.deployer.ssh.transport">Transport protocol: </label></th>
+        <th><label for="jetbrains.buildServer.deployer.ssh.transport">Transport protocol: </label></th>
         <td>
             <props:selectProperty name="<%=SSHRunnerConstants.PARAM_TRANSPORT%>">
-                <props:option value="<%=SSHRunnerConstants.TRANSPORT_SCP%>">SCP</props:option>
-                <props:option value="<%=SSHRunnerConstants.TRANSPORT_SFTP%>">SFTP</props:option>
+                <c:forEach var="type" items="${runnerConst.transportTypeValues}">
+                    <props:option value="${type.key}"><c:out value="${type.value}"/></props:option>
+                </c:forEach>
             </props:selectProperty>
-            <span class="smallNote">Use SFTP protocol instead of SCP (default)</span>
+            <span class="smallNote">Select SSH transfer protocol to use</span>
+        </td>
+    </tr>
+    <tr>
+        <th><label for="jetbrains.buildServer.sshexec.port">Port: </label></th>
+        <td><props:textProperty name="<%=SSHRunnerConstants.PARAM_PORT%>"  className="longField" maxlength="256"/>
+            <span class="smallNote">Optional. Default value: 22</span>
         </td>
     </tr>
 </l:settingsGroup>
 
 <l:settingsGroup title="Deployment Credentials">
     <tr>
-        <th><label for="my.buildServer.deployer.myUsername">Username:</label></th>
+        <th><label for="jetbrains.buildServer.deployer.username">Username:</label></th>
         <td><props:textProperty name="<%=DeployerRunnerConstants.PARAM_USERNAME%>"  className="longField" maxlength="256"/>
             <span class="smallNote">Enter username</span>
         </td>
     </tr>
     <tr>
-        <th><label for="my.buildServer.deployer.myPassword">Password:</label></th>
+        <th><label for="jetbrains.buildServer.deployer.password">Password:</label></th>
         <td><props:passwordProperty name="<%=DeployerRunnerConstants.PARAM_PASSWORD%>"  className="longField" maxlength="256"/>
             <span class="smallNote">Enter password</span>
         </td>
 
 <l:settingsGroup title="Deployment source">
     <tr>
-        <th><label for="my.buildServer.deployer.sourcePath">Artifacts path: </label></th>
+        <th><label for="jetbrains.buildServer.deployer.sourcePath">Artifacts path: </label></th>
         <td>
             <props:multilineProperty name="<%=DeployerRunnerConstants.PARAM_SOURCE_PATH%>" className="longField" cols="30" rows="4" expanded="true" linkTitle="Enter artifacts paths"/>
             <span class="smallNote">New line or comma separated paths to build artifacts. Ant-style wildcards like dir/**/*.zip and target directories like *.zip => winFiles,unix/distro.tgz => linuxFiles, where winFiles and linuxFiles are target directories are supported.</span>

deploy-runner/deploy-runner-server/src/main/resources/buildServerResources/editSSHExecParams.jsp

 
 <l:settingsGroup title="Deployment Target">
     <tr>
-        <th><label for="my.buildServer.sshexec.host">Hostname: </label></th>
+        <th><label for="jetbrains.buildServer.sshexec.host">Hostname: </label></th>
         <td><props:textProperty name="<%=SSHRunnerConstants.PARAM_HOST%>"  className="longField" maxlength="256"/>
-            <span class="smallNote">Enter hostname</span>
+            <span class="smallNote">Enter hostname or IP address</span>
+        </td>
+    </tr>
+    <tr>
+        <th><label for="jetbrains.buildServer.sshexec.port">Port: </label></th>
+        <td><props:textProperty name="<%=SSHRunnerConstants.PARAM_PORT%>"  className="longField" maxlength="256"/>
+            <span class="smallNote">Optional. Default value: 22</span>
         </td>
     </tr>
 </l:settingsGroup>
 
 <l:settingsGroup title="Deployment Credentials">
     <tr>
-        <th><label for="my.buildServer.sshexec.username">Username:</label></th>
+        <th><label for="jetbrains.buildServer.sshexec.username">Username:</label></th>
         <td><props:textProperty name="<%=SSHRunnerConstants.PARAM_USERNAME%>"  className="longField" maxlength="256"/>
             <span class="smallNote">Enter username</span>
         </td>
     </tr>
     <tr>
-        <th><label for="my.buildServer.sshexec.password">Password:</label></th>
+        <th><label for="jetbrains.buildServer.sshexec.password">Password:</label></th>
         <td><props:passwordProperty name="<%=SSHRunnerConstants.PARAM_PASSWORD%>"  className="longField" maxlength="256"/>
             <span class="smallNote">Enter password</span>
         </td>
     </tr>
 </l:settingsGroup>
 
-<l:settingsGroup title="Deployment source">
+<l:settingsGroup title="SSH Commands">
     <tr>
-        <th><label for="my.buildServer.sshexec.command">Commands: </label></th>
+        <th><label for="jetbrains.buildServer.sshexec.command">Commands: </label></th>
         <td>
-            <props:textProperty name="<%=SSHRunnerConstants.PARAM_COMMAND%>"  className="longField" expandable="true"/>
+            <props:multilineProperty name="<%=SSHRunnerConstants.PARAM_COMMAND%>"  className="longField" rows="4" cols="30" expanded="true" linkTitle="Enter remote commands"/>
             <span class="smallNote">Enter newline delimited set of commands to run</span>
         </td>
     </tr>

deploy-runner/deploy-runner-server/src/main/resources/buildServerResources/editSmbDeployerParams.jsp

 
 <l:settingsGroup title="Deployment Target">
     <tr>
-        <th><label for="my.buildServer.deployer.targetUrl">Target URL: </label></th>
+        <th><label for="jetbrains.buildServer.deployer.targetUrl">Target URL: </label></th>
         <td><props:textProperty name="<%=DeployerRunnerConstants.PARAM_TARGET_URL%>"  className="longField" maxlength="256"/>
             <span class="smallNote">Enter target url, e.g. \\host\share\subdir</span>
         </td>
 
 <l:settingsGroup title="Deployment Credentials">
     <tr>
-        <th><label for="my.buildServer.deployer.myUsername">Username:</label></th>
+        <th><label for="jetbrains.buildServer.deployer.username">Username:</label></th>
         <td><props:textProperty name="<%=DeployerRunnerConstants.PARAM_USERNAME%>"  className="longField" maxlength="256"/>
             <span class="smallNote">Enter username</span>
         </td>
     </tr>
     <tr>
-        <th><label for="my.buildServer.deployer.myPassword">Password:</label></th>
+        <th><label for="jetbrains.buildServer.deployer.password">Password:</label></th>
         <td><props:passwordProperty name="<%=DeployerRunnerConstants.PARAM_PASSWORD%>"  className="longField" maxlength="256"/>
             <span class="smallNote">Enter password</span>
         </td>
     </tr>
+    <tr>
+        <th><label for="jetbrains.buildServer.deployer.domain">Domain:</label></th>
+        <td><props:textProperty name="<%=DeployerRunnerConstants.PARAM_DOMAIN%>"  className="longField" maxlength="256"/>
+            <span class="smallNote">Enter domain</span>
+        </td>
+    </tr>
 </l:settingsGroup>
 
 <l:settingsGroup title="Deployment source">
     <tr>
-        <th><label for="my.buildServer.deployer.sourcePath">Artifacts path: </label></th>
+        <th><label for="jetbrains.buildServer.deployer.sourcePath">Artifacts path: </label></th>
         <td>
             <props:multilineProperty name="<%=DeployerRunnerConstants.PARAM_SOURCE_PATH%>" className="longField" cols="30" rows="4" expanded="true" linkTitle="Enter artifacts paths"/>
             <span class="smallNote">New line or comma separated paths to build artifacts. Ant-style wildcards like dir/**/*.zip and target directories like *.zip => winFiles,unix/distro.tgz => linuxFiles, where winFiles and linuxFiles are target directories are supported.</span>

deploy-runner/deploy-runner-server/src/main/resources/buildServerResources/editTomcatDeployerParams.jsp

 
 <l:settingsGroup title="Deployment Target">
     <tr>
-        <th><label for="my.buildServer.deployer.targetUrl">Target URL: </label></th>
+        <th><label for="jetbrains.buildServer.deployer.targetUrl">Target server: </label></th>
         <td><props:textProperty name="<%=DeployerRunnerConstants.PARAM_TARGET_URL%>"  className="longField" maxlength="256"/>
-            <span class="smallNote">Enter target url</span>
+            <span class="smallNote">Enter target Tomcat server hostname or IP. "Manager" application must be installed on targer server</span>
         </td>
     </tr>
 </l:settingsGroup>
 
 <l:settingsGroup title="Deployment Credentials">
     <tr>
-        <th><label for="my.buildServer.deployer.myUsername">Username:</label></th>
+        <th><label for="jetbrains.buildServer.deployer.username">Username:</label></th>
         <td><props:textProperty name="<%=DeployerRunnerConstants.PARAM_USERNAME%>"  className="longField" maxlength="256"/>
-            <span class="smallNote">Enter myUsername</span>
+            <span class="smallNote">Enter username. The user must have "manager-script" role assigned</span>
         </td>
     </tr>
     <tr>
-        <th><label for="my.buildServer.deployer.myPassword">Password:</label></th>
+        <th><label for="jetbrains.buildServer.deployer.password">Password:</label></th>
         <td><props:passwordProperty name="<%=DeployerRunnerConstants.PARAM_PASSWORD%>"  className="longField" maxlength="256"/>
-            <span class="smallNote">Enter myPassword</span>
+            <span class="smallNote">Enter password</span>
         </td>
     </tr>
 </l:settingsGroup>
 
-<l:settingsGroup title="Deployment source">
+<l:settingsGroup title="Web applicatoin settings">
     <tr>
-        <th><label for="my.buildServer.deployer.sourcePath">Source directory: </label></th>
+        <th><label for="jetbrains.buildServer.deployer.sourcePath">Path to WAR archive: </label></th>
         <td><props:textProperty name="<%=DeployerRunnerConstants.PARAM_SOURCE_PATH%>"  className="longField" maxlength="256"/>
-            <span class="smallNote">Enter path to source</span>
+            <span class="smallNote">Path to war archive to deploy</span>
+        </td>
+    </tr>
+    <tr>
+        <th><label for="jetbrains.buildServer.deployer.tomcat.contextPath">Context path: </label></th>
+        <td><props:textProperty name="<%=DeployerRunnerConstants.PARAM_TOMCAT_CONTEXT_PATH%>"  className="longField" maxlength="256"/>
+            <span class="smallNote">Optional. Context path on server, defaults to war archive name</span>
         </td>
     </tr>
 </l:settingsGroup>

deploy-runner/deploy-runner-server/src/main/resources/buildServerResources/viewFtpDeployerParams.jsp

 <jsp:useBean id="propertiesBean" scope="request" type="jetbrains.buildServer.controllers.BasePropertiesBean"/>
 
 <div class="parameter">
-  Target url: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_TARGET_URL%>" emptyValue="default"/></strong>
+  FTP server: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_TARGET_URL%>" emptyValue="default"/></strong>
 </div>
 
 <div class="parameter">
-  Username: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_USERNAME%>" emptyValue="default"/></strong>
+  Username: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_USERNAME%>" emptyValue="none"/></strong>
 </div>
 
 <div class="parameter">
-  Password: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_PASSWORD%>" emptyValue="default"/></strong>
-</div>
-
-<div class="parameter">
-  Source: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_SOURCE_PATH%>" emptyValue="default"/></strong>
+  Source: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_SOURCE_PATH%>" emptyValue="none"/></strong>
 </div>

deploy-runner/deploy-runner-server/src/main/resources/buildServerResources/viewSSHDeployerParams.jsp

 <%@ page import="jetbrains.buildServer.deployer.common.DeployerRunnerConstants" %>
+<%@ page import="jetbrains.buildServer.deployer.common.SSHRunnerConstants" %>
 <%@ taglib prefix="props" tagdir="/WEB-INF/tags/props" %>
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<jsp:useBean id="runnerConst" scope="request" class="jetbrains.buildServer.deployer.common.SSHRunnerConstants"/>
 <jsp:useBean id="propertiesBean" scope="request" type="jetbrains.buildServer.controllers.BasePropertiesBean"/>
 
 <div class="parameter">
-  Target url: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_TARGET_URL%>" emptyValue="default"/></strong>
+  Target host: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_TARGET_URL%>" emptyValue="default"/></strong>
 </div>
 
 <div class="parameter">
-  Username: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_USERNAME%>" emptyValue="default"/></strong>
+  Target port: <strong><props:displayValue name="<%=SSHRunnerConstants.PARAM_PORT%>" emptyValue="default"/></strong>
 </div>
 
 <div class="parameter">
-  Password: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_PASSWORD%>" emptyValue="default"/></strong>
+  Username: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_USERNAME%>" emptyValue="none"/></strong>
 </div>
 
 <div class="parameter">
-  Source: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_SOURCE_PATH%>" emptyValue="default"/></strong>
+  Transport: <strong><c:forEach var="type" items="${runnerConst.transportTypeValues}"><c:if test="${type.key == propertiesBean.properties[runnerConst.transportType]}"><c:out value="${type.value}"/></c:if></c:forEach></strong>
+</div>
+
+<div class="parameter">
+  Source: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_SOURCE_PATH%>" emptyValue="none"/></strong>
 </div>

deploy-runner/deploy-runner-server/src/main/resources/buildServerResources/viewSSHExecParams.jsp

 <%@ page import="jetbrains.buildServer.deployer.common.SSHRunnerConstants" %>
+<%@ page import="jetbrains.buildServer.deployer.common.DeployerRunnerConstants" %>
 <%@ taglib prefix="props" tagdir="/WEB-INF/tags/props" %>
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 <jsp:useBean id="propertiesBean" scope="request" type="jetbrains.buildServer.controllers.BasePropertiesBean"/>
 
 <div class="parameter">
-  Target url: <strong><props:displayValue name="<%=SSHRunnerConstants.PARAM_HOST%>" emptyValue="default"/></strong>
+  Target host: <strong><props:displayValue name="<%=SSHRunnerConstants.PARAM_HOST%>" emptyValue="default"/></strong>
 </div>
 
 <div class="parameter">
-  Username: <strong><props:displayValue name="<%=SSHRunnerConstants.PARAM_USERNAME%>" emptyValue="default"/></strong>
+  Target port: <strong><props:displayValue name="<%=SSHRunnerConstants.PARAM_PORT%>" emptyValue="default"/></strong>
 </div>
 
 <div class="parameter">
-  Password: <strong><props:displayValue name="<%=SSHRunnerConstants.PARAM_PASSWORD%>" emptyValue="default"/></strong>
+  Username: <strong><props:displayValue name="<%=SSHRunnerConstants.PARAM_USERNAME%>" emptyValue="none"/></strong>
 </div>
 
 <div class="parameter">
-  Commands: <strong><props:displayValue name="<%=SSHRunnerConstants.PARAM_COMMAND%>" emptyValue="default"/></strong>
+  Commands: <strong><props:displayValue name="<%=SSHRunnerConstants.PARAM_COMMAND%>" emptyValue="none"/></strong>
 </div>

deploy-runner/deploy-runner-server/src/main/resources/buildServerResources/viewSmbDeployerParams.jsp

 <jsp:useBean id="propertiesBean" scope="request" type="jetbrains.buildServer.controllers.BasePropertiesBean"/>
 
 <div class="parameter">
-  Target url: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_TARGET_URL%>" emptyValue="default"/></strong>
+  Target share: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_TARGET_URL%>" emptyValue="default"/></strong>
 </div>
 
 <div class="parameter">
-  Username: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_USERNAME%>" emptyValue="default"/></strong>
+  Domain: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_DOMAIN%>" emptyValue="empty"/></strong>
 </div>
 
 <div class="parameter">
-  Password: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_PASSWORD%>" emptyValue="default"/></strong>
+  Username: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_USERNAME%>" emptyValue="none"/></strong>
 </div>
 
 <div class="parameter">
-  Source: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_SOURCE_PATH%>" emptyValue="default"/></strong>
+  Source: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_SOURCE_PATH%>" emptyValue="none"/></strong>
 </div>

deploy-runner/deploy-runner-server/src/main/resources/buildServerResources/viewTomcatDeployerParams.jsp

 <jsp:useBean id="propertiesBean" scope="request" type="jetbrains.buildServer.controllers.BasePropertiesBean"/>
 
 <div class="parameter">
-  Target url: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_TARGET_URL%>" emptyValue="default"/></strong>
+  Tomcat server: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_TARGET_URL%>" emptyValue="default"/></strong>
 </div>
 
 <div class="parameter">
-  Username: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_USERNAME%>" emptyValue="default"/></strong>
+  Username: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_USERNAME%>" emptyValue="none"/></strong>
 </div>
 
 <div class="parameter">
-  Password: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_PASSWORD%>" emptyValue="default"/></strong>
-</div>
-
-<div class="parameter">
-  Source: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_SOURCE_PATH%>" emptyValue="default"/></strong>
+  WAR archive: <strong><props:displayValue name="<%=DeployerRunnerConstants.PARAM_SOURCE_PATH%>" emptyValue="not defined"/></strong>
 </div>

deploy-runner/gradle.properties

-path.variable.teamcitydistribution=c:/Program Files/JetBrains/TeamCity
 pluginName = deploy-runner

deploy-runner/settings.gradle

+rootProject.name = "${pluginName}"
 include "${pluginName}-agent", "${pluginName}-server", "${pluginName}-common"
Add a comment to this file

deploy-runner/wrapper/gradle-wrapper.jar

Binary file removed.

deploy-runner/wrapper/gradle-wrapper.properties

-#Sat Mar 24 13:24:16 MSK 2012
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
-distributionUrl=http://services.gradle.org/distributions/gradle-1.0-milestone-9-bin.zip
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.