diff --git a/build.gradle b/build.gradle index ad8a2a4..0a05dfa 100644 --- a/build.gradle +++ b/build.gradle @@ -122,7 +122,7 @@ configurations { } ext { - xlPlatformVersion = "2016.2.6" + xlPlatformVersion = "2017.7.1" } diff --git a/src/main/java/com/xebialabs/deployit/ci/DeployitPerformer.java b/src/main/java/com/xebialabs/deployit/ci/DeployitPerformer.java index 0a5778a..d4439ca 100644 --- a/src/main/java/com/xebialabs/deployit/ci/DeployitPerformer.java +++ b/src/main/java/com/xebialabs/deployit/ci/DeployitPerformer.java @@ -8,7 +8,9 @@ import java.io.File; import java.io.IOException; +import java.util.HashMap; import java.util.List; +import java.util.Map; import com.google.common.base.Joiner; import com.google.common.base.Strings; @@ -127,8 +129,15 @@ public boolean doPerform() throws InterruptedException, IOException { final String versionId = Joiner.on("/").join(resolvedApplication, packageVersion); deploymentListener.info(Messages.DeployitNotifier_deploy(versionId, resolvedEnvironment)); + + Map deploymentProperties = new HashMap(); + if (deploymentParameters.deploymentOptions.deploymentProperties != null) { + for (DeploymentProperty deploymentProperty : deploymentParameters.deploymentOptions.deploymentProperties) { + deploymentProperties.put(deploymentProperty.propertyName, envVars.expand(deploymentProperty.propertyValue)); + } + } try { - deployitServer.deploy(versionId, resolvedEnvironment, deploymentParameters.deploymentOptions, deploymentListener); + deployitServer.deploy(versionId, resolvedEnvironment, deploymentProperties, deploymentParameters.deploymentOptions, deploymentListener); } catch (Exception e) { deploymentListener.error(Messages._DeployitNotifier_errorDeploy(e.getMessage())); return false; @@ -181,4 +190,4 @@ public DeployitPerformerParameters(JenkinsPackageOptions packageOptions, List { + + public static String PROPERTY_TYPE = "udm.DeployedApplication"; + + @Override + public String getDisplayName() { + return DeploymentProperty.class.getSimpleName(); + } + + public ListBoxModel doFillPropertyNameItems( + @QueryParameter(value = "credential") @RelativePath(value = "../..") String credentialExistingProps, + @QueryParameter(value = "credential") @RelativePath(value = "..") String credentialNewProps, + @AncestorInPath AbstractProject project) { + String creds = credentialExistingProps != null ? credentialExistingProps : credentialNewProps; + Credential overridingCredential = RepositoryUtils.retrieveOverridingCredentialFromProject(project); + // load type descriptor + DeployitServer deployitServer = RepositoryUtils.getDeployitServer(creds, overridingCredential); + DeployitDescriptorRegistry descriptorRegistry = deployitServer.getDescriptorRegistry(); + Collection properties = descriptorRegistry.getPropertiesForDeployableType(PROPERTY_TYPE, ONLY_SIMPLE_EDITABLE_PROPERTIES); + return ListBoxModels.of(properties); + } + + } + +} diff --git a/src/main/java/com/xebialabs/deployit/ci/JenkinsDeploymentOptions.java b/src/main/java/com/xebialabs/deployit/ci/JenkinsDeploymentOptions.java index 8837d7d..61a9ae8 100644 --- a/src/main/java/com/xebialabs/deployit/ci/JenkinsDeploymentOptions.java +++ b/src/main/java/com/xebialabs/deployit/ci/JenkinsDeploymentOptions.java @@ -57,18 +57,20 @@ public class JenkinsDeploymentOptions implements Describable deploymentProperties; public final VersionKind versionKind; public String version; @DataBoundConstructor - public JenkinsDeploymentOptions(String environment, VersionKind versionKind, boolean generateDeployedOnUpgrade, boolean skipMode, boolean testMode, boolean rollbackOnError) { + public JenkinsDeploymentOptions(String environment, VersionKind versionKind, boolean generateDeployedOnUpgrade, boolean skipMode, boolean testMode, boolean rollbackOnError, List deploymentProperties) { this.generateDeployedOnUpgrade = generateDeployedOnUpgrade; this.skipMode = skipMode; this.testMode = testMode; this.rollbackOnError = rollbackOnError; this.environment = environment; this.versionKind = versionKind; + this.deploymentProperties = deploymentProperties; } @Override diff --git a/src/main/java/com/xebialabs/deployit/ci/dar/RemotePackaging.java b/src/main/java/com/xebialabs/deployit/ci/dar/RemotePackaging.java index 006789d..d2b6c5d 100644 --- a/src/main/java/com/xebialabs/deployit/ci/dar/RemotePackaging.java +++ b/src/main/java/com/xebialabs/deployit/ci/dar/RemotePackaging.java @@ -77,14 +77,24 @@ public RemotePackaging withRegistryVersion(String registryVersion) { return this; } + private DarPackager getDarPackager() { + ClassLoader origClassLoader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(DarPackager.class.getClassLoader()); + ManifestWriter mw = new ManifestXmlWriter(); + return new DarPackager(mw); + } finally { + Thread.currentThread().setContextClassLoader(origClassLoader); + } + } + /** * Call to be executed via jenkins virtual channel */ @Override public String call() throws RuntimeException { targetDir.mkdirs(); - ManifestWriter mw = new ManifestXmlWriter(); - DarPackager pkger = new DarPackager(mw); + DarPackager pkger = getDarPackager(); DescriptorRegistry descriptorRegistry = DescriptorRegistry.getDescriptorRegistry(booterConfig); if (null == descriptorRegistry) { SlaveRemoteDescriptorRegistry.boot(descriptors, booterConfig, registryVersion); diff --git a/src/main/java/com/xebialabs/deployit/ci/server/AbstractDeploymentCommand.java b/src/main/java/com/xebialabs/deployit/ci/server/AbstractDeploymentCommand.java new file mode 100644 index 0000000..0a2e560 --- /dev/null +++ b/src/main/java/com/xebialabs/deployit/ci/server/AbstractDeploymentCommand.java @@ -0,0 +1,134 @@ +package com.xebialabs.deployit.ci.server; + +import com.google.common.base.Throwables; +import com.xebialabs.deployit.ci.DeployitPluginException; +import com.xebialabs.deployit.ci.util.JenkinsDeploymentListener; +import com.xebialabs.deployit.engine.api.TaskService; +import com.xebialabs.deployit.engine.api.execution.StepExecutionState; +import com.xebialabs.deployit.engine.api.execution.StepState; +import com.xebialabs.deployit.engine.api.execution.TaskExecutionState; +import com.xebialabs.deployit.engine.api.execution.TaskState; +import org.apache.commons.lang.StringUtils; + +import java.text.SimpleDateFormat; +import java.util.GregorianCalendar; +import java.util.List; + +import static com.google.common.collect.Lists.newArrayList; +import static java.lang.String.format; + +public abstract class AbstractDeploymentCommand { + + protected TaskService taskService; + protected JenkinsDeploymentListener listener; + + protected AbstractDeploymentCommand(TaskService taskService, JenkinsDeploymentListener listener) { + this.taskService = taskService; + this.listener = listener; + } + + protected boolean executeTask(String taskId, boolean skipMode, boolean testMode) { + + if (skipMode) { + listener.info("skip mode, skip all the steps"); + taskService.skip(taskId, range(taskService.getTask(taskId).getNrSteps() + 1)); + } + + checkTaskState(taskId); + if (testMode) { + listener.info("test mode, cancel task " + taskId); + taskService.cancel(taskId); + return false; + } + + try { + listener.info("Start deployment task " + taskId); + startTaskAndWait(taskId); + checkTaskState(taskId); + taskService.archive(taskId); + return true; + } catch (RuntimeException e) { + String msg = format("Error when executing task %s", taskId); + throw new DeployitPluginException(msg); + } + + } + + private List range(int end) { + List result = newArrayList(); + for (int i = 1; i < end; i++) { + result.add(i); + } + return result; + } + + private void checkTaskState(String taskId) { + TaskState taskState = taskService.getTask(taskId); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss"); + listener.info(format("%s Description %s", taskId, taskState.getDescription())); + listener.info(format("%s State %s %d/%d", taskId, taskState.getState(), taskState.getCurrentStepNr(), taskState.getNrSteps())); + if (taskState.getStartDate() != null) { + final GregorianCalendar startDate = taskState.getStartDate().toGregorianCalendar(); + listener.info(format("%s Start %s", taskId, sdf.format(startDate.getTime()))); + } + + if (taskState.getCompletionDate() != null) { + final GregorianCalendar completionDate = taskState.getCompletionDate().toGregorianCalendar(); + listener.info(format("%s Completion %s", taskId, sdf.format(completionDate.getTime()))); + } + + StringBuilder sb = new StringBuilder(); + for (int i = 1; i <= taskState.getNrSteps(); i++) { + final StepState stepInfo = taskService.getStep(taskId, i, null); + final String description = stepInfo.getDescription(); + final String log = stepInfo.getLog(); + String stepInfoMessage; + if (StringUtils.isEmpty(log) || description.equals(log)) { + stepInfoMessage = format("%s step #%d %s\t%s", taskId, i, stepInfo.getState(), description); + } else { + stepInfoMessage = format("%s step #%d %s\t%s\n%s", taskId, i, stepInfo.getState(), description, log); + } + + listener.info(stepInfoMessage); + if (StepExecutionState.FAILED.equals(stepInfo.getState())) + sb.append(stepInfoMessage); + } + + if (taskState.getState().isExecutionHalted()) + throw new DeployitPluginException(format("Errors when executing task %s: %s", taskId, sb)); + } + + private void startTaskAndWait(String taskId) { + taskService.start(taskId); + // Wait until done/failed + boolean done = false; + TaskState ti; + + int retryCount = 1; + while (!done) { + try { + ti = taskService.getTask(taskId); + TaskExecutionState state = ti.getState(); + listener.debug("Task state: " + state.toString()); + done = state.isPassiveAfterExecuting(); + retryCount = 1; + } catch (Exception e) { + if (retryCount == 6) { //fail after 5 consecutive errors. + Throwables.propagate(e); + } else { + listener.info("Failed to get task status. Error message: " + Throwables.getRootCause(e).getMessage()); + listener.info("Will attempt retry " + retryCount + " of 5 in one second."); + retryCount++; + } + } + + try { + listener.debug("Waiting for task to be done..."); + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + +} diff --git a/src/main/java/com/xebialabs/deployit/ci/server/DeployCommand.java b/src/main/java/com/xebialabs/deployit/ci/server/DeployCommand.java index 9d0aa7c..751e640 100644 --- a/src/main/java/com/xebialabs/deployit/ci/server/DeployCommand.java +++ b/src/main/java/com/xebialabs/deployit/ci/server/DeployCommand.java @@ -26,6 +26,7 @@ import java.text.SimpleDateFormat; import java.util.GregorianCalendar; import java.util.List; +import java.util.Map; import org.apache.commons.lang.StringUtils; @@ -87,7 +88,7 @@ private void verifyPackageExistInRemoteRepository(String deploymentPackage) { } - public void deploy(String deploymentPackage, String environment) { + public void deploy(String deploymentPackage, String environment, Map deploymentProperties) { listener.debug(deploymentOptions.toString()); verifyPackageExistInRemoteRepository(deploymentPackage); @@ -108,6 +109,11 @@ public void deploy(String deploymentPackage, String environment) { deployment = deploymentService.prepareAutoDeployeds(deployment); } + for (Map.Entry deploymentProperty : deploymentProperties.entrySet()) { + listener.debug(String.format("Setting deployment property %s = %s", deploymentProperty.getKey(), deploymentProperty.getValue())); + deployment.getDeployedApplication().setProperty(deploymentProperty.getKey(), deploymentProperty.getValue()); + } + listener.debug(" dump Deployeds"); for (ConfigurationItem itemDto : deployment.getDeployeds()) { listener.debug(" - " + itemDto); @@ -264,4 +270,4 @@ private void startTaskAndWait(String taskId) { } } } -} \ No newline at end of file +} diff --git a/src/main/java/com/xebialabs/deployit/ci/server/DeployitDescriptorRegistry.java b/src/main/java/com/xebialabs/deployit/ci/server/DeployitDescriptorRegistry.java index d866890..e4c5d6e 100644 --- a/src/main/java/com/xebialabs/deployit/ci/server/DeployitDescriptorRegistry.java +++ b/src/main/java/com/xebialabs/deployit/ci/server/DeployitDescriptorRegistry.java @@ -19,6 +19,8 @@ public interface DeployitDescriptorRegistry extends Versioned { String UDM_ARTIFACT = "udm.Artifact"; String UDM_DEPLOYABLE = "udm.Deployable"; String UDM_EMBEDDED_DEPLOYABLE = "udm.EmbeddedDeployable"; + String UDM_DEPLOYED_APPLICATION = "udm.DeployedApplication"; + String UDM_CONTAINER = "udm.Container"; Type typeForClass(Class clazz); diff --git a/src/main/java/com/xebialabs/deployit/ci/server/DeployitDescriptorRegistryImpl.java b/src/main/java/com/xebialabs/deployit/ci/server/DeployitDescriptorRegistryImpl.java index 56248f9..966c2e0 100644 --- a/src/main/java/com/xebialabs/deployit/ci/server/DeployitDescriptorRegistryImpl.java +++ b/src/main/java/com/xebialabs/deployit/ci/server/DeployitDescriptorRegistryImpl.java @@ -31,6 +31,7 @@ import com.xebialabs.deployit.ci.ArtifactView; import com.xebialabs.deployit.ci.util.Strings2; +import com.xebialabs.deployit.plugin.api.udm.base.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,11 +62,6 @@ import com.xebialabs.deployit.plugin.api.udm.Version; import com.xebialabs.deployit.plugin.api.udm.artifact.FolderArtifact; import com.xebialabs.deployit.plugin.api.udm.artifact.SourceArtifact; -import com.xebialabs.deployit.plugin.api.udm.base.BaseConfigurationItem; -import com.xebialabs.deployit.plugin.api.udm.base.BaseDeployable; -import com.xebialabs.deployit.plugin.api.udm.base.BaseDeployableFileArtifact; -import com.xebialabs.deployit.plugin.api.udm.base.BaseDeployableFolderArtifact; -import com.xebialabs.deployit.plugin.api.udm.base.BaseEmbeddedDeployable; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newHashSet; @@ -217,6 +213,15 @@ public ConfigurationItem newInstance(String typeName, String name) { return ci; } + private Object getPropertyDescriptorDefaultValue(RemoteDescriptor remoteDescriptor, String propertyName) { + for (PropertyDescriptor pd : remoteDescriptor.getPropertyDescriptors()) { + if (propertyName.equals(pd.getName())) { + return pd.getDefaultValue(); + } + } + return null; + } + private ConfigurationItem newInstance(Type type, String id) { try { RemoteDescriptor remoteDescriptor = (RemoteDescriptor) getDescriptor(type); @@ -231,6 +236,7 @@ private ConfigurationItem newInstance(Type type, String id) { } else { ci = new BaseDeployableFileArtifact(); } + ((BaseDeployableArtifact) ci).setTextFileNamesRegex(String.valueOf(getPropertyDescriptorDefaultValue(remoteDescriptor, "textFileNamesRegex"))); } else if (remoteDescriptor.isAssignableTo(typeForClass(Deployable.class))) { ci = new BaseDeployable(); } else { diff --git a/src/main/java/com/xebialabs/deployit/ci/server/DeployitServer.java b/src/main/java/com/xebialabs/deployit/ci/server/DeployitServer.java index e44fdb2..3f7f01f 100644 --- a/src/main/java/com/xebialabs/deployit/ci/server/DeployitServer.java +++ b/src/main/java/com/xebialabs/deployit/ci/server/DeployitServer.java @@ -1,6 +1,7 @@ package com.xebialabs.deployit.ci.server; import java.util.List; +import java.util.Map; import com.xebialabs.deployit.booter.remote.BooterConfig; import com.xebialabs.deployit.booter.remote.DeployitCommunicator; @@ -22,7 +23,11 @@ public interface DeployitServer { ConfigurationItem importPackage(String darFile); - void deploy(String deploymentPackage, String environment, JenkinsDeploymentOptions deploymentOptions, JenkinsDeploymentListener listener); + void deploy(String deploymentPackage, String environment, Map deploymentProperties, JenkinsDeploymentOptions deploymentOptions, JenkinsDeploymentListener listener); + + void undeploy(String deployedApplication, JenkinsDeploymentListener listener); + + void executeControlTask(String hostId, String controlTask, Map parameters, JenkinsDeploymentListener listener); DeployitCommunicator newCommunicator(); diff --git a/src/main/java/com/xebialabs/deployit/ci/server/DeployitServerImpl.java b/src/main/java/com/xebialabs/deployit/ci/server/DeployitServerImpl.java index b979434..d14e400 100644 --- a/src/main/java/com/xebialabs/deployit/ci/server/DeployitServerImpl.java +++ b/src/main/java/com/xebialabs/deployit/ci/server/DeployitServerImpl.java @@ -2,7 +2,9 @@ import java.util.Collections; import java.util.List; +import java.util.Map; +import com.xebialabs.deployit.engine.api.ControlService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,13 +84,28 @@ public ConfigurationItem importPackage(final String darFile) { } @Override - public void deploy(String deploymentPackage, String environment, JenkinsDeploymentOptions deploymentOptions, JenkinsDeploymentListener listener) { + public void deploy(String deploymentPackage, String environment, Map deploymentProperties, JenkinsDeploymentOptions deploymentOptions, JenkinsDeploymentListener listener) { DeploymentService deploymentService = getCommunicator().getProxies().getDeploymentService(); TaskService taskService = getCommunicator().getProxies().getTaskService(); RepositoryService repositoryService = getCommunicator().getProxies().getRepositoryService(); - new DeployCommand(deploymentService, taskService, repositoryService, deploymentOptions, listener).deploy(deploymentPackage, environment); + new DeployCommand(deploymentService, taskService, repositoryService, deploymentOptions, listener).deploy(deploymentPackage, environment, deploymentProperties); } + @Override + public void undeploy(String deployedApplication, JenkinsDeploymentListener listener) { + DeploymentService deploymentService = getCommunicator().getProxies().getDeploymentService(); + TaskService taskService = getCommunicator().getProxies().getTaskService(); + RepositoryService repositoryService = getCommunicator().getProxies().getRepositoryService(); + new UndeployCommand(taskService, listener, deploymentService, repositoryService).undeploy(deployedApplication); + } + + @Override + public void executeControlTask(String hostId, String controlTask, Map parameters, JenkinsDeploymentListener listener) { + TaskService taskService = getCommunicator().getProxies().getTaskService(); + ControlService controlService = getCommunicator().getProxies().getControlService(); + RepositoryService repositoryService = getCommunicator().getProxies().getRepositoryService(); + new ExecuteControlTaskCommand(taskService, listener, controlService, repositoryService).executeControlTask(hostId, controlTask, parameters); + } @Override public DeployitCommunicator newCommunicator() { @@ -141,4 +158,4 @@ public String getRegistryVersion() { return getDescriptorRegistry().getVersion(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/xebialabs/deployit/ci/server/ExecuteControlTaskCommand.java b/src/main/java/com/xebialabs/deployit/ci/server/ExecuteControlTaskCommand.java new file mode 100644 index 0000000..d8386c9 --- /dev/null +++ b/src/main/java/com/xebialabs/deployit/ci/server/ExecuteControlTaskCommand.java @@ -0,0 +1,56 @@ +package com.xebialabs.deployit.ci.server; + +import com.xebialabs.deployit.ci.DeployitPluginException; +import com.xebialabs.deployit.ci.util.JenkinsDeploymentListener; +import com.xebialabs.deployit.engine.api.ControlService; +import com.xebialabs.deployit.engine.api.RepositoryService; +import com.xebialabs.deployit.engine.api.TaskService; +import com.xebialabs.deployit.engine.api.dto.Control; +import com.xebialabs.deployit.plugin.api.reflect.Type; +import com.xebialabs.deployit.plugin.api.udm.ConfigurationItem; + +import java.util.Map; + +public class ExecuteControlTaskCommand extends AbstractDeploymentCommand { + + private ControlService controlService; + private RepositoryService repositoryService; + + protected ExecuteControlTaskCommand(TaskService taskService, JenkinsDeploymentListener listener, ControlService controlService, RepositoryService repositoryService) { + super(taskService, listener); + this.controlService = controlService; + this.repositoryService = repositoryService; + } + + public void executeControlTask(String hostId, String controlTask, Map parameters) { + verifyHost(hostId); + Control control = controlService.prepare(controlTask, hostId); + for (Map.Entry parameter : parameters.entrySet()) { + control.getParameters().setProperty(parameter.getKey(), parameter.getValue()); + } + String taskId = controlService.createTask(control); + try { + executeTask(taskId, false, false); + } catch (RuntimeException e) { + throw new DeployitPluginException(e.getMessage()); + } + } + + private void verifyHost(String hostId) { + try { + ConfigurationItem repoPackage = repositoryService.read(hostId); + listener.debug(String.format("Found CI '%s' as '%s' .", repoPackage, repoPackage.getType())); + + Type deployedApplicationType = Type.valueOf(DeployitDescriptorRegistry.UDM_CONTAINER); + if (!repoPackage.getType().instanceOf(deployedApplicationType)) { + String errorMsg = String.format("'%s' of type '%s' is not a container.", hostId, repoPackage.getType()); + throw new DeployitPluginException(errorMsg); + } + } + catch (Throwable t) { + String errorMsg = String.format("'%s' not found in repository.", hostId); + throw new DeployitPluginException(errorMsg, t); + } + } + +} diff --git a/src/main/java/com/xebialabs/deployit/ci/server/UndeployCommand.java b/src/main/java/com/xebialabs/deployit/ci/server/UndeployCommand.java new file mode 100644 index 0000000..ea1ac57 --- /dev/null +++ b/src/main/java/com/xebialabs/deployit/ci/server/UndeployCommand.java @@ -0,0 +1,62 @@ +package com.xebialabs.deployit.ci.server; + +import com.xebialabs.deployit.ci.DeployitPluginException; +import com.xebialabs.deployit.ci.util.JenkinsDeploymentListener; +import com.xebialabs.deployit.engine.api.DeploymentService; +import com.xebialabs.deployit.engine.api.RepositoryService; +import com.xebialabs.deployit.engine.api.TaskService; +import com.xebialabs.deployit.engine.api.dto.Deployment; +import com.xebialabs.deployit.plugin.api.reflect.Type; +import com.xebialabs.deployit.plugin.api.udm.ConfigurationItem; + +public class UndeployCommand extends AbstractDeploymentCommand { + + private DeploymentService deploymentService; + private RepositoryService repositoryService; + + public UndeployCommand(TaskService taskService, JenkinsDeploymentListener listener, DeploymentService deploymentService, RepositoryService repositoryService) { + super(taskService, listener); + this.deploymentService = deploymentService; + this.repositoryService = repositoryService; + } + + public void undeploy(String deployedApplication) { + verifyDeployedApplication(deployedApplication); + Deployment deployment = deploymentService.prepareUndeploy(deployedApplication); + try { + deployment = deploymentService.validate(deployment); + } catch (RuntimeException e) { + listener.error(" RuntimeException: " + e.getMessage()); + if (!e.getMessage().contains("The task did not deliver any steps")) { + throw new DeployitPluginException(e.getMessage(), e); + } + return; + } + + String taskId = deploymentService.createTask(deployment); + + try { + executeTask(taskId, false, false); + } catch (RuntimeException e) { + throw new DeployitPluginException(e.getMessage()); + } + } + + private void verifyDeployedApplication(String deployedApplication) { + try { + ConfigurationItem repoPackage = repositoryService.read(deployedApplication); + listener.debug(String.format("Found CI '%s' as '%s' .", repoPackage, repoPackage.getType())); + + Type deployedApplicationType = Type.valueOf(DeployitDescriptorRegistry.UDM_DEPLOYED_APPLICATION); + if (!repoPackage.getType().instanceOf(deployedApplicationType)) { + String errorMsg = String.format("'%s' of type '%s' is not a deployed application.", deployedApplication, repoPackage.getType()); + throw new DeployitPluginException(errorMsg); + } + } + catch (Throwable t) { + String errorMsg = String.format("'%s' not found in repository.", deployedApplication); + throw new DeployitPluginException(errorMsg, t); + } + } + +} diff --git a/src/main/java/com/xebialabs/deployit/ci/workflow/XLDeployControlTaskStep.java b/src/main/java/com/xebialabs/deployit/ci/workflow/XLDeployControlTaskStep.java new file mode 100644 index 0000000..3fd731b --- /dev/null +++ b/src/main/java/com/xebialabs/deployit/ci/workflow/XLDeployControlTaskStep.java @@ -0,0 +1,95 @@ +package com.xebialabs.deployit.ci.workflow; + +import com.google.inject.Inject; +import com.xebialabs.deployit.ci.DeployitNotifier; +import com.xebialabs.deployit.ci.RepositoryUtils; +import com.xebialabs.deployit.ci.server.DeployitServer; +import com.xebialabs.deployit.ci.util.JenkinsDeploymentListener; +import hudson.EnvVars; +import hudson.Extension; +import hudson.model.TaskListener; +import hudson.util.ListBoxModel; +import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; +import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; +import org.jenkinsci.plugins.workflow.steps.AbstractSynchronousNonBlockingStepExecution; +import org.jenkinsci.plugins.workflow.steps.StepContextParameter; +import org.kohsuke.stapler.DataBoundConstructor; + +import java.util.HashMap; +import java.util.Map; + + +public class XLDeployControlTaskStep extends AbstractStepImpl { + + public final String serverCredentials; + public final String hostId; + public final String controlTask; + public final Map parameters; + + @DataBoundConstructor + public XLDeployControlTaskStep(String serverCredentials, String hostId, String controlTask, Map parameters) { + this.serverCredentials = serverCredentials; + this.hostId = hostId; + this.controlTask = controlTask; + this.parameters = parameters; + } + + @Extension + public static final class XLDeployControlTaskStepDescriptor extends AbstractStepDescriptorImpl { + + private DeployitNotifier.DeployitDescriptor deployitDescriptor; + + public XLDeployControlTaskStepDescriptor() { + super(XLDeployControlTaskExecution.class); + deployitDescriptor = new DeployitNotifier.DeployitDescriptor(); + } + + @Override + public String getFunctionName() { + return "xldControlTask"; + } + + @Override + public String getDisplayName() { + return "Execute a control task"; + } + + public ListBoxModel doFillServerCredentialsItems() { + return getDeployitDescriptor().doFillCredentialItems(); + } + + private DeployitNotifier.DeployitDescriptor getDeployitDescriptor() { + deployitDescriptor.load(); + return deployitDescriptor; + } + + } + + public static final class XLDeployControlTaskExecution extends AbstractSynchronousNonBlockingStepExecution { + + @Inject + private transient XLDeployControlTaskStep step; + + @StepContextParameter + private transient EnvVars envVars; + + @StepContextParameter + private transient TaskListener listener; + + @Override + protected Void run() throws Exception { + String resolvedHostId = envVars.expand(step.hostId); + Map resolvedParameters = new HashMap<>(); + if (step.parameters != null) { + for (Map.Entry parameter : step.parameters.entrySet()) { + resolvedParameters.put(envVars.expand(parameter.getKey()), envVars.expand(parameter.getValue())); + } + } + JenkinsDeploymentListener deploymentListener = new JenkinsDeploymentListener(listener, false); + DeployitServer deployitServer = RepositoryUtils.getDeployitServer(step.serverCredentials, null); + deployitServer.executeControlTask(resolvedHostId, step.controlTask, resolvedParameters, deploymentListener); + return null; + } + + } +} diff --git a/src/main/java/com/xebialabs/deployit/ci/workflow/XLDeployDeployStep.java b/src/main/java/com/xebialabs/deployit/ci/workflow/XLDeployDeployStep.java index 442f047..0333181 100644 --- a/src/main/java/com/xebialabs/deployit/ci/workflow/XLDeployDeployStep.java +++ b/src/main/java/com/xebialabs/deployit/ci/workflow/XLDeployDeployStep.java @@ -17,6 +17,9 @@ import org.jenkinsci.plugins.workflow.steps.StepContextParameter; import org.kohsuke.stapler.DataBoundConstructor; +import java.util.HashMap; +import java.util.Map; + public class XLDeployDeployStep extends AbstractStepImpl { @@ -24,6 +27,7 @@ public class XLDeployDeployStep extends AbstractStepImpl { public final String packageId; public final String environmentId; public final String overrideCredentialId; + public final Map deploymentProperties = null; @DataBoundConstructor public XLDeployDeployStep(String serverCredentials, String overrideCredentialId, String packageId, @@ -81,10 +85,14 @@ protected Void run() throws Exception { String resolvedEnvironmentId = envVars.expand(step.environmentId); String resolvedPackageId = envVars.expand(step.packageId); JenkinsDeploymentListener deploymentListener = new JenkinsDeploymentListener(listener, false); - JenkinsDeploymentOptions deploymentOptions = new JenkinsDeploymentOptions(resolvedEnvironmentId, VersionKind.Other, true, false , false, true); + JenkinsDeploymentOptions deploymentOptions = new JenkinsDeploymentOptions(resolvedEnvironmentId, VersionKind.Other, true, false , false, true, null); DeployitServer deployitServer = RepositoryUtils.getDeployitServerFromCredentialsId( step.serverCredentials, step.overrideCredentialId); - deployitServer.deploy(resolvedPackageId,resolvedEnvironmentId,deploymentOptions,deploymentListener); + Map deploymentProperties = step.deploymentProperties; + if (deploymentProperties == null) { + deploymentProperties = new HashMap(); + } + deployitServer.deploy(resolvedPackageId,resolvedEnvironmentId, deploymentProperties,deploymentOptions,deploymentListener); return null; } diff --git a/src/main/java/com/xebialabs/deployit/ci/workflow/XLDeployUndeployStep.java b/src/main/java/com/xebialabs/deployit/ci/workflow/XLDeployUndeployStep.java new file mode 100644 index 0000000..c97715f --- /dev/null +++ b/src/main/java/com/xebialabs/deployit/ci/workflow/XLDeployUndeployStep.java @@ -0,0 +1,82 @@ +package com.xebialabs.deployit.ci.workflow; + +import com.google.inject.Inject; +import com.xebialabs.deployit.ci.DeployitNotifier; +import com.xebialabs.deployit.ci.RepositoryUtils; +import com.xebialabs.deployit.ci.server.DeployitServer; +import com.xebialabs.deployit.ci.util.JenkinsDeploymentListener; +import hudson.EnvVars; +import hudson.Extension; +import hudson.model.TaskListener; +import hudson.util.ListBoxModel; +import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; +import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; +import org.jenkinsci.plugins.workflow.steps.AbstractSynchronousNonBlockingStepExecution; +import org.jenkinsci.plugins.workflow.steps.StepContextParameter; +import org.kohsuke.stapler.DataBoundConstructor; + + +public class XLDeployUndeployStep extends AbstractStepImpl { + + public final String serverCredentials; + public final String deployedApplicationId; + + @DataBoundConstructor + public XLDeployUndeployStep(String serverCredentials, String deployedApplicationId) { + this.serverCredentials = serverCredentials; + this.deployedApplicationId = deployedApplicationId; + } + + @Extension + public static final class XLDeployDeployStepDescriptor extends AbstractStepDescriptorImpl { + + private DeployitNotifier.DeployitDescriptor deployitDescriptor; + + public XLDeployDeployStepDescriptor() { + super(XLDeployUndeployExecution.class); + deployitDescriptor = new DeployitNotifier.DeployitDescriptor(); + } + + @Override + public String getFunctionName() { + return "xldUndeploy"; + } + + @Override + public String getDisplayName() { + return "Undeploy a deployed application"; + } + + public ListBoxModel doFillServerCredentialsItems() { + return getDeployitDescriptor().doFillCredentialItems(); + } + + private DeployitNotifier.DeployitDescriptor getDeployitDescriptor() { + deployitDescriptor.load(); + return deployitDescriptor; + } + + } + + public static final class XLDeployUndeployExecution extends AbstractSynchronousNonBlockingStepExecution { + + @Inject + private transient XLDeployUndeployStep step; + + @StepContextParameter + private transient EnvVars envVars; + + @StepContextParameter + private transient TaskListener listener; + + @Override + protected Void run() throws Exception { + String resolvedDeployedApplicationId = envVars.expand(step.deployedApplicationId); + JenkinsDeploymentListener deploymentListener = new JenkinsDeploymentListener(listener, false); + DeployitServer deployitServer = RepositoryUtils.getDeployitServer(step.serverCredentials, null); + deployitServer.undeploy(resolvedDeployedApplicationId, deploymentListener); + return null; + } + + } +} diff --git a/src/main/java/com/xebialabs/xltype/serialization/xstream/XStreamReaderWriter.java b/src/main/java/com/xebialabs/xltype/serialization/xstream/XStreamReaderWriter.java index 0c6b182..4bc095b 100644 --- a/src/main/java/com/xebialabs/xltype/serialization/xstream/XStreamReaderWriter.java +++ b/src/main/java/com/xebialabs/xltype/serialization/xstream/XStreamReaderWriter.java @@ -23,6 +23,7 @@ package com.xebialabs.xltype.serialization.xstream; +import com.thoughtworks.xstream.converters.DataHolder; import hudson.PluginFirstClassLoader; import java.io.IOException; @@ -179,13 +180,11 @@ private boolean canBeConverted(Class type) { @Override public Object readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { logger.trace("Reading {}", genericType); - return read(entityStream, type, httpHeaders.getFirst("BOOTER_CONFIG")); + return xStream.unmarshal(HIERARCHICAL_STREAM_DRIVER.createReader(entityStream), null, createDataHolder()); } - private Object read(InputStream entityStream, Class type, String booterConfigKey) { - MapBackedDataHolder dataHolder = new MapBackedDataHolder(); - dataHolder.put("BOOTER_CONFIG", booterConfigKey); - return xStream.unmarshal(HIERARCHICAL_STREAM_DRIVER.createReader(entityStream), null, dataHolder); + protected DataHolder createDataHolder() { + return null; } private static final Logger logger = LoggerFactory.getLogger(XStreamReaderWriter.class); diff --git a/src/main/resources/com/xebialabs/deployit/ci/JenkinsDeploymentOptions/config.jelly b/src/main/resources/com/xebialabs/deployit/ci/JenkinsDeploymentOptions/config.jelly index 6eadd89..94c965f 100644 --- a/src/main/resources/com/xebialabs/deployit/ci/JenkinsDeploymentOptions/config.jelly +++ b/src/main/resources/com/xebialabs/deployit/ci/JenkinsDeploymentOptions/config.jelly @@ -21,5 +21,25 @@ + + + + + + + + + + + + + +
+ +
+
+
+
+
diff --git a/src/main/webapp/help-deployment-properties.html b/src/main/webapp/help-deployment-properties.html new file mode 100644 index 0000000..1d1cc6f --- /dev/null +++ b/src/main/webapp/help-deployment-properties.html @@ -0,0 +1,3 @@ +
+ Specify properties to set on the deployed package. You can use Jenkins Env variables. +
diff --git a/src/test/java/com/xebialabs/deployit/ci/server/DeployCommandTest.java b/src/test/java/com/xebialabs/deployit/ci/server/DeployCommandTest.java index 7dff88d..7850c4d 100644 --- a/src/test/java/com/xebialabs/deployit/ci/server/DeployCommandTest.java +++ b/src/test/java/com/xebialabs/deployit/ci/server/DeployCommandTest.java @@ -24,6 +24,7 @@ package com.xebialabs.deployit.ci.server; import java.nio.charset.Charset; +import java.util.HashMap; import org.junit.Test; @@ -48,7 +49,7 @@ public void shouldRetryTaskStatusCheckFiveTimesAfterExceptionOccurs() { DeploymentService deploymentService = mock(DeploymentService.class); TaskService taskService = mock(TaskService.class); RepositoryService repositoryService = mock(RepositoryService.class); - JenkinsDeploymentOptions jenkinsOptions = new JenkinsDeploymentOptions("test", VersionKind.Packaged, false, false, false, false); + JenkinsDeploymentOptions jenkinsOptions = new JenkinsDeploymentOptions("test", VersionKind.Packaged, false, false, false, false, null); JenkinsDeploymentListener jenkinsDeploymentListener = new JenkinsDeploymentListener(new StreamBuildListener(System.out, Charset.defaultCharset()), true); DeployCommand deployCommand = new DeployCommand(deploymentService, taskService, repositoryService, jenkinsOptions, jenkinsDeploymentListener); @@ -70,7 +71,7 @@ public void shouldRetryTaskStatusCheckFiveTimesAfterExceptionOccurs() { .thenThrow(new MyTestValidationException("Expect this to be rethrown")); try { - deployCommand.deploy("pkg", "test"); + deployCommand.deploy("pkg", "test", new HashMap()); fail("Expected exception after 5 failed attempts."); } catch (MyTestValidationException e ) { //success