diff --git a/.gitignore b/.gitignore index ea9ae04..75637ff 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ *.iml *.ipr *.iws +pom.properties diff --git a/README.md b/README.md index cac0f68..634e853 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,11 @@ The compiled plugin is available for download on the [IBM UrbanCode website](htt Plug-ins downloaded directly from the [IBM UrbanCode Plug-ins microsite](https://developer.ibm.com/urbancode/plugins) are fully supported by IBM. Create a GitHub Issue or Pull Request for minor requests and bug fixes. For time sensitive issues that require immediate assistance, [file a PMR](https://www-947.ibm.com/support/servicerequest/newServiceRequest.action) through the normal IBM support channels. Plug-ins built externally or modified with custom code are supported on a best-effort-basis using GitHub Issues. ### Locally Build the Plug-in -This open source plug-in uses Ant as its build tool. [Install the latest version of Ant](http://ant.apache.org/manual/install.html) to build the plug-in locally. Build the plug-in by running the `ant` command in the plug-in's root directory. The plug-in distributable will be placed under the `dist` folder. +This open source plug-in uses Gradle as its build tool. [Install the latest version of Gradle](https://gradle.org/install) to build the plug-in locally. Build the plug-in by running the `gradle jpi` command in the plug-in's root directory. The plug-in distributable will be placed under the `build/libs` folder. ## Pipeline Examples +Full explanation of these Pipeline syntax examples can be found on our [Jenkins Pipeline Syntax](https://developer.ibm.com/urbancode/plugindoc/ibmucd/jenkins-pipeline-formerly-jenkins-2-0/2-2/jenkins-pipeline-syntax-overview/) documentation. + ### Create Component Version ```groovy node { @@ -33,8 +35,7 @@ node { fileIncludePatterns: '*.zip', fileExcludePatterns: '', pushProperties: 'jenkins.server=Local\njenkins.reviewed=false', - pushDescription: 'Pushed from Jenkins', - pushIncremental: false + pushDescription: 'Pushed from Jenkins' ] ] ]) @@ -46,6 +47,10 @@ node { node { step([$class: 'UCDeployPublisher', siteName: 'local', + component: [ + $class: 'com.urbancode.jenkins.plugins.ucdeploy.VersionHelper$VersionBlock', + componentName: 'Jenkins' + ], deploy: [ $class: 'com.urbancode.jenkins.plugins.ucdeploy.DeployHelper$DeployBlock', deployApp: 'Jenkins', @@ -88,11 +93,67 @@ node { ``` ## Release Notes +### Version 2.21 +Update dependencies for compatibility for jenkins 2.2. + +### Version 2.20 +RFE 147414 : Added ucd application process log url for more details. + +### Version 2.19 +Fixed : Addition of latest version to specified component only instead of all components. + +### Version 2.18 +Fixed APAR PH28324 - UCD Jenkins Plugin - Fail the Jenkins job if nothing is found to push to UCD( avoid false positive). + +### Version 2.17 +Block "Run as Alternative User" : Help text added for "Alternative Username" and "Alternative Password". + +### Version 2.16 +Fixed APAR PH25862 - Making deploy version "not required" field to support following, which needs no version: +1. Operational component process. +2. Application generic process. + +### Version 2.15 +Fixed APAR PH23739 - Fixed : Jenkins Plugin Shows success on Canceled job in UCD + +### Version 2.14 +Fixing CVE:CVE-2019-4233 + +### Version 2.13 +Modified process to continue if user is unable to set environment variable. + +### Version 2.12 +Set component version as environment variable when pushing a new version. + +### Version 2.11 +Added option to skip waiting for a successful deployment from UCD. + +### Version 2.10 +Added functionality to preemptively create environment snapshot to use during deployment. + +### Version 2.9 +Fixed 401 http error when setting version properties by using latest uDeployRestClient. + +### Version 2.8 +Fixed all Null pointer and bad casting exceptions returned in Jenkins system logs upon saving a job. +Removed administrative checkbox from global and job configuration of user credentials. + +### Version 2.7 +Fixed APAR PI91900 - Unfilled application process properties unable to be checked with a snapshot. +### Version 2.6 +Fixed APAR PI85407 - Importing component versions no longer fails when runtime properties aren't provided. + +### Version 2.5 +RFE 104275 - Support for Description and Application Request Properties on deployments. + +### Version 2.4 +Fixed APAR PI80038 - Snapshot names no longer require a leading equals sign. + ### Version 2.3 Fixed APAR PI77548 - Component process properties failing to resolve on deployment. ### Version 2.2 -Fixed RFE 98375 - Jenkins Plugin only allows Global credentials instead of job-based credentials. +RFE 98375 - Jenkins Plugin only allows Global credentials instead of job-based credentials. Fixed PI75045 - UCD server maintenance mode check requires admin privileges. diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..c283871 --- /dev/null +++ b/build.gradle @@ -0,0 +1,65 @@ +/** + * (c) Copyright IBM Corporation 2017. + * This is licensed under the following license. + * The Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + * U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. + */ + +import groovy.util.XmlSlurper +plugins { + id "org.jenkins-ci.jpi" version "0.16.0" +} + +group = "com.urbancode.ds.jenkins.plugins" +version = getVersion() +description = "Publish artifacts into an IBM UrbanCode Deploy component as a build step." + +jenkinsPlugin { + coreVersion = "1.587" // Version of Jenkins core this plugin depends on. + displayName = "IBM UrbanCode Deploy Jenkins Pipeline Plugin" // Human-readable name of plugin. + url = "https://developer.ibm.com/urbancode/plugin/jenkins-2-0/" // URL for plugin on Jenkins wiki or elsewhere. + gitHubUrl = "https://github.com/IBM-UrbanCode" // Plugin URL on GitHub. Optional. + shortName = "ibm-ucdeploy-pipeline-open" // Plugin ID, defaults to the project name without trailing '-plugin' + + // The developers section is optional, and corresponds to the POM developers section. + developers {[ + developer { + id "nhmathis" + name "Nicholas Mathison" + email "nhmathis(at)us(dot)ibm(dot)com" + }, + developer { + id "jrbarto" + name "Jeffrey Barto" + email "jrbarto(at)us(dot)ibm(dot)com" + } + ]} +} + +repositories { + mavenCentral() + maven { + url "https://public.dhe.ibm.com/software/products/UrbanCode/maven2/" + } +} + +dependencies { + compile 'com.ibm.urbancode.commons:uDeployRestClient:+' + // compile 'com.ibm.urbancode.commons:CommonsFileUtils:+' + // compile 'com.ibm.urbancode.commons:HttpComponents-Util:+' + // compile 'com.ibm.urbancode.commons:CommonsUtil:+' + // compile 'com.sun.jersey:jersey-core:1.12' + // compile 'com.sun.jersey:jersey-client:1.12' + compile 'javax.ws.rs:jsr311-api:1.1.1' + // compile 'org.codehaus.jettison:jettison:1.1' + // compile 'commons-lang:commons-lang:2.5' + // compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3.4' + // compile group: 'org.apache.httpcomponents', name: 'httpcore', version: '4.3.4' + // compile group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.3.4' +} + +def getVersion() { + def pomFile = new XmlSlurper().parseText(new File("pom.xml").text) + def version = pomFile.version.text() + return version.replace('${env.buildLife}', "open") +} diff --git a/build.xml b/build.xml index ffb526d..b055b0b 100644 --- a/build.xml +++ b/build.xml @@ -1,4 +1,4 @@ - + @@ -12,16 +12,13 @@ PROJECT CONFIGURATION ================================================================== --> + - - + - - - @@ -48,8 +45,6 @@ - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/dependencies.xml b/dependencies.xml index 4b919d5..b347c42 100644 --- a/dependencies.xml +++ b/dependencies.xml @@ -29,7 +29,7 @@ - + lib @@ -75,22 +75,6 @@ - - - - - lib - - - - - - - - lib - - - @@ -101,7 +85,7 @@ - + lib diff --git a/ivy.xml b/ivy.xml deleted file mode 100644 index a39952d..0000000 --- a/ivy.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ivysettings.xml b/ivysettings.xml deleted file mode 100644 index 2c92389..0000000 --- a/ivysettings.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/pom.xml b/pom.xml index 8174cb5..38b175c 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ IBM UrbanCode Deploy Pipeline (Build Steps) Plugin com.urbancode.jenkins.plugins ibm-ucdeploy-build-steps - 2.3.${env.buildLife} + 2.20.${env.buildLife} hpi https://developer.ibm.com/urbancode/plugin/jenkins/ @@ -97,22 +97,22 @@ org.apache.httpcomponents httpclient - 4.3.3 + 4.5.10 org.apache.httpcomponents httpcore - 4.3.3 + 4.4.13 org.apache.httpcomponents httpclient-cache - 4.3.3 + 4.5.10 org.apache.httpcomponents httpmime - 4.3.3 + 4.5.10 com.kenai.nbpwr diff --git a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/ComponentHelper.java b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/ComponentHelper.java index ac4d44d..1dc2417 100644 --- a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/ComponentHelper.java +++ b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/ComponentHelper.java @@ -1,5 +1,5 @@ /** - * © Copyright IBM Corporation 2017. + * (c) Copyright IBM Corporation 2017. * This is licensed under the following license. * The Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) * U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. diff --git a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/DeliveryHelper.java b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/DeliveryHelper.java index 4588c93..0d28f6a 100644 --- a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/DeliveryHelper.java +++ b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/DeliveryHelper.java @@ -1,5 +1,5 @@ /** - * © Copyright IBM Corporation 2017. + * (c) Copyright IBM Corporation 2017. * This is licensed under the following license. * The Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) * U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. diff --git a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/DeployHelper.java b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/DeployHelper.java index c176ab0..d05639b 100644 --- a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/DeployHelper.java +++ b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/DeployHelper.java @@ -1,10 +1,10 @@ /** - * © Copyright IBM Corporation 2017. + * (c) Copyright IBM Corporation 2017. * This is licensed under the following license. * The Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) * U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ - + package com.urbancode.jenkins.plugins.ucdeploy; import hudson.AbortException; @@ -22,7 +22,9 @@ import java.util.UUID; import org.apache.http.impl.client.DefaultHttpClient; +import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; import org.kohsuke.stapler.DataBoundConstructor; import com.urbancode.jenkins.plugins.ucdeploy.ProcessHelper; @@ -39,10 +41,11 @@ public class DeployHelper { private ApplicationClient appClient; private TaskListener listener; private EnvVars envVars; - private String description = "Requested from Jenkins"; + private URI ucdUrl; public DeployHelper(URI ucdUrl, DefaultHttpClient httpClient, TaskListener listener, EnvVars envVars) { - appClient = new ApplicationClient(ucdUrl, httpClient); + this.ucdUrl = ucdUrl; + appClient = new ApplicationClient(ucdUrl, httpClient); this.listener = listener; this.envVars = envVars; } @@ -51,9 +54,12 @@ public static class DeployBlock { private String deployApp; private String deployEnv; private String deployProc; + private Boolean skipWait; private CreateProcessBlock createProcess; private CreateSnapshotBlock createSnapshot; private String deployVersions; + private String deployReqProps; + private String deployDesc; private Boolean deployOnlyChanged; @DataBoundConstructor @@ -61,17 +67,23 @@ public DeployBlock( String deployApp, String deployEnv, String deployProc, + Boolean skipWait, CreateProcessBlock createProcess, CreateSnapshotBlock createSnapshot, String deployVersions, + String deployReqProps, + String deployDesc, Boolean deployOnlyChanged) { this.deployApp = deployApp; this.deployEnv = deployEnv; this.deployProc = deployProc; + this.skipWait = skipWait; this.createProcess = createProcess; this.createSnapshot = createSnapshot; this.deployVersions = deployVersions; + this.deployReqProps = deployReqProps; + this.deployDesc = deployDesc; this.deployOnlyChanged = deployOnlyChanged; } @@ -102,12 +114,21 @@ public String getDeployProc() { } } - public CreateProcessBlock getCreateProcessBlock() { + public CreateProcessBlock getCreateProcess() { return createProcess; } + public Boolean getSkipWait() { + if (skipWait != null) { + return skipWait; + } + else { + return false; + } + } + public Boolean createProcessChecked() { - if (getCreateProcessBlock() == null) { + if (getCreateProcess() == null) { return false; } else { @@ -115,12 +136,12 @@ public Boolean createProcessChecked() { } } - public CreateSnapshotBlock getCreateSnapshotBlock() { + public CreateSnapshotBlock getCreateSnapshot() { return createSnapshot; } public Boolean createSnapshotChecked() { - if (getCreateSnapshotBlock() == null) { + if (getCreateSnapshot() == null) { return false; } else { @@ -137,6 +158,24 @@ public String getDeployVersions() { } } + public String getDeployReqProps() { + if (deployReqProps != null) { + return deployReqProps; + } + else { + return ""; + } + } + + public String getDeployDesc() { + if (deployDesc != null) { + return deployDesc; + } + else { + return ""; + } + } + public Boolean getDeployOnlyChanged() { if (deployOnlyChanged != null) { return deployOnlyChanged; @@ -149,33 +188,62 @@ public Boolean getDeployOnlyChanged() { public static class CreateSnapshotBlock { private String snapshotName; + private Boolean deployWithSnapshot; + private Boolean includeOnlyDeployVersions; @DataBoundConstructor - public CreateSnapshotBlock(String snapshotName) { + public CreateSnapshotBlock(String snapshotName, Boolean deployWithSnapshot, Boolean includeOnlyDeployVersions) { this.snapshotName = snapshotName; + this.deployWithSnapshot = deployWithSnapshot; + this.includeOnlyDeployVersions = includeOnlyDeployVersions; } public String getSnapshotName() { return snapshotName; } + + public Boolean getDeployWithSnapshot() { + if (deployWithSnapshot != null) { + return deployWithSnapshot; + } + else { + return false; + } + } + + public Boolean getIncludeOnlyDeployVersions() { + if (includeOnlyDeployVersions != null) { + return includeOnlyDeployVersions; + } + else { + return false; + } + } } /** * Deploys a version in IBM UrbanCode Deploys * * @param deployBlock The DeployBlock containing the structure of the deployment - * @throws AbortException + * @throws JSONException + * @throws IOException */ - public void deployVersion(DeployBlock deployBlock) throws AbortException { + public void runDeployment(DeployBlock deployBlock) throws IOException, JSONException { String deployApp = envVars.expand(deployBlock.getDeployApp()); String deployEnv = envVars.expand(deployBlock.getDeployEnv()); String deployProc = envVars.expand(deployBlock.getDeployProc()); + Boolean skipWait = deployBlock.getSkipWait(); String deployVersions = envVars.expand(deployBlock.getDeployVersions()); + String deployReqProps = envVars.expand(deployBlock.getDeployReqProps()); + String deployDesc = envVars.expand(deployBlock.getDeployDesc()); + CreateSnapshotBlock createSnapshot = deployBlock.getCreateSnapshot(); + Boolean doCreateSnapshot = deployBlock.createSnapshotChecked(); + Map requestProperties = readProperties(deployReqProps); // create process if (deployBlock.createProcessChecked()) { ProcessHelper processHelper = new ProcessHelper(appClient, listener, envVars); - processHelper.createProcess(deployApp, deployProc, deployBlock.getCreateProcessBlock()); + processHelper.createProcess(deployApp, deployProc, deployBlock.getCreateProcess()); } // required fields @@ -188,45 +256,107 @@ public void deployVersion(DeployBlock deployBlock) throws AbortException { if (deployProc.isEmpty()) { throw new AbortException("Deploy Process is a required field for deployment."); } + + /*Commenting to support following : + 1. Operational component process which needs no version. + 2. Running application generic process + */ + /* if (deployVersions.isEmpty()) { throw new AbortException("Deploy Versions is a required field for deployment."); } + */ - // deploy + /* Deploy logic */ String snapshot = ""; Map> componentVersions = new HashMap>(); - if (deployVersions.contains("=")) { - if (deployVersions.contains("\n")) { - throw new AbortException("Only a single SNAPSHOT can be specified"); + UUID appProcUUID; + + /* Create snapshot preemptively to deploy */ + if (doCreateSnapshot && createSnapshot.getDeployWithSnapshot()) { + snapshot = envVars.expand(createSnapshot.getSnapshotName()); + doCreateSnapshot = false; // Set to false so reactive snapshot isn't created also + + if (deployVersions.toUpperCase().startsWith("SNAPSHOT=")) { + listener.getLogger().println("[Warning] When deploying with a build environment snapshot," + + " you may not specify additional snapshots in the 'Snapshot/Component Versions' box." + + " This field will be ignored for this deployment."); + } + else { + componentVersions = readComponentVersions(deployVersions); // Versions to add to new snapshot + } + + listener.getLogger().println("Creating environment snapshot '" + snapshot + + "' in UrbanCode Deploy."); + + if (createSnapshot.getIncludeOnlyDeployVersions()) { + appClient.createSnapshot(snapshot, deployDesc, deployApp, componentVersions); + } else { + appClient.createSnapshotOfEnvironment(deployEnv, deployApp, snapshot, deployDesc); + } + + + listener.getLogger().println("Acquiring all versions of the snapshot."); + JSONArray snapshotVersions = appClient.getSnapshotVersions(snapshot, deployApp); + Map compVersionMap = new HashMap(); + + /* Create a map of component name to a list of its versions in the snapshot */ + for (int i = 0; i < snapshotVersions.length(); i++) { + JSONObject snapshotComponent = snapshotVersions.getJSONObject(i); + String name = snapshotComponent.getString("name"); + JSONArray versions = snapshotComponent.getJSONArray("desiredVersions"); + + compVersionMap.put(name, versions); } - snapshot = deployVersions; + + for (Map.Entry> entry : componentVersions.entrySet()) { + String component = entry.getKey(); + JSONArray oldVersions = compVersionMap.get(component); + + /* Remove past versions of the deployment component from the snapshot */ + if (oldVersions != null && oldVersions.length() > 0) { + for (int i = 0 ; i < oldVersions.length(); i++) { + JSONObject oldVersion = oldVersions.getJSONObject(i); + String oldVersionName = oldVersion.getString("name"); + String oldVersionId = oldVersion.getString("id"); + + listener.getLogger().println("Removing past version '" + oldVersionName + + "' of component '" + component + "' from snapshot."); + appClient.removeVersionFromSnapshot(snapshot, deployApp, oldVersionId, component); + } + } + + /* Add each version for this component to the snapshot */ + for (String version : entry.getValue()) { + listener.getLogger().println("Adding component version '" + version + + "' of component '" + component + "' to snapshot."); + appClient.addVersionToSnapshot(snapshot, deployApp, version, component); + } + } + listener.getLogger().println("Deploying SNAPSHOT '" + snapshot + "'"); } + /* Deploy with component versions or a pre-existing snapshot */ else { - componentVersions = readComponentVersions(deployVersions); - listener.getLogger().println("Deploying component versions '" + componentVersions + "'"); + if (deployVersions.toUpperCase().startsWith("SNAPSHOT=")) { + if (deployVersions.contains("\n")) { + throw new AbortException("Only a single SNAPSHOT can be specified"); + } + snapshot = deployVersions.replaceFirst("(?i)SNAPSHOT=", ""); + listener.getLogger().println("Deploying SNAPSHOT '" + snapshot + "'"); + } + else { + componentVersions = readComponentVersions(deployVersions); + listener.getLogger().println("Deploying component versions '" + componentVersions + "'"); + } } + appProcUUID = deploy(deployApp, deployProc, deployDesc, deployEnv, snapshot, componentVersions, + deployBlock.getDeployOnlyChanged(), requestProperties); + listener.getLogger().println("Starting deployment process '" + deployProc + "' of application '" + deployApp + "' in environment '" + deployEnv + "'"); - UUID appProcUUID; - try { - appProcUUID = appClient.requestApplicationProcess(deployApp, - deployProc, - description, - deployEnv, - snapshot, - deployBlock.getDeployOnlyChanged(), - componentVersions); - } - catch (IOException ex) { - throw new AbortException("Could not request application process: " + ex.getMessage()); - } - catch (JSONException ex) { - throw new AbortException("An error occurred while processing the JSON object for the application process " + - "request: " + ex.getMessage()); - } listener.getLogger().println("Deployment request id is: '" + appProcUUID.toString() + "'"); listener.getLogger().println("Deployment is running. Waiting for UCD Server feedback."); @@ -235,55 +365,86 @@ public void deployVersion(DeployBlock deployBlock) throws AbortException { boolean processFinished = false; String deploymentResult = ""; - while (!processFinished) { - deploymentResult = checkDeploymentProcessResult(appProcUUID.toString()); + /* Wait for process to finish unless skipping the wait */ + if (!skipWait) { + while (!processFinished) { + deploymentResult = checkDeploymentProcessResult(appProcUUID.toString()); - if (!deploymentResult.isEmpty() - && !deploymentResult.equalsIgnoreCase("NONE") - && !deploymentResult.equalsIgnoreCase("SCHEDULED FOR FUTURE")) { - processFinished = true; + if (!deploymentResult.isEmpty() + && !deploymentResult.equalsIgnoreCase("NONE") + && !deploymentResult.equalsIgnoreCase("SCHEDULED FOR FUTURE")) { + processFinished = true; - if (deploymentResult.equalsIgnoreCase("FAULTED") || deploymentResult.equalsIgnoreCase("FAILED TO START")) { - throw new AbortException("Deployment process failed with result " + deploymentResult); + if (deploymentResult.equalsIgnoreCase("FAULTED") || deploymentResult.equalsIgnoreCase("FAILED TO START") || deploymentResult.equalsIgnoreCase("CANCELED")) { + throw new AbortException("Deployment process failed with result " + deploymentResult); + } } - } - // give application process more time to complete - try { - Thread.sleep(3000); - } - catch (InterruptedException ex) { - throw new AbortException("Could not wait to check deployment result: " + ex.getMessage()); + // give application process more time to complete + try { + Thread.sleep(3000); + } + catch (InterruptedException ex) { + throw new AbortException("Could not wait to check deployment result: " + ex.getMessage()); + } } } + else { + listener.getLogger().println("'Skip Wait' option selected. Returning immmediately " + + "without waiting for the UCD process to complete."); + } - // create snapshot of environment - if (deployBlock.createSnapshotChecked()) { - try { - CreateSnapshotBlock createSnapshot = deployBlock.getCreateSnapshotBlock(); - String snapshotName = envVars.expand(createSnapshot.getSnapshotName()); - String description = "Snapshot of successful build environment."; - - listener.getLogger().println("Creating environment snapshot '" + snapshotName - + "' in UrbanCode Deploy."); - appClient.createSnapshotOfEnvironment(deployEnv, deployApp, snapshotName, description); - listener.getLogger().println("Successfully created environment snapshot."); - } - catch (IOException ex) { - throw new AbortException("Failed to create envrionment snapshot: " + ex.getMessage()); - } - catch (JSONException ex) { - throw new AbortException("An error occurred while processing the JSON object for the snapshot " + - "request: " + ex.getMessage()); - } + /* create snapshot of environment reactively, as a result of successful deployment */ + if (doCreateSnapshot) { + String snapshotName = envVars.expand(createSnapshot.getSnapshotName()); + listener.getLogger().println("Creating environment snapshot '" + snapshotName + + "' in UrbanCode Deploy."); + appClient.createSnapshotOfEnvironment(deployEnv, deployApp, snapshotName, deployDesc); + listener.getLogger().println("Successfully created environment snapshot."); } long duration = (new Date().getTime() - startTime) / 1000; listener.getLogger().println("Finished the deployment in " + duration + " seconds"); listener.getLogger().println("The deployment result is " + deploymentResult + ". See the UrbanCode Deploy deployment " + - "logs for details."); + "logs for details : " + ucdUrl + "/#applicationProcessRequest/" + appProcUUID.toString()); + } + + private UUID deploy( + String application, + String appProcess, + String description, + String environment, + String snapshot, + Map> componentVersions, + Boolean deployOnlyChanged, + Map requestProperties) + throws IOException, JSONException { + + // Confirm all application request properties are fulfilled (not done by UCD) + JSONArray unfilledProps = appClient.checkUnfilledApplicationProcessRequestProperties(application, + appProcess, snapshot, requestProperties); + if (unfilledProps.length() > 0) { + List props = new ArrayList(); + for (int i = 0; i < unfilledProps.length(); i++) { + String propName = unfilledProps.getJSONObject(i).getString("name"); + props.add(propName); + } + throw new AbortException("Required UrbanCode Deploy Application Process request properties were " + + "not supplied: " + props.toString()); + } + + // Run the application process + UUID appProcUUID = appClient.requestApplicationProcess(application, + appProcess, + description, + environment, + snapshot, + deployOnlyChanged, + componentVersions, + requestProperties); + return appProcUUID; } /** @@ -323,6 +484,32 @@ private Map> readComponentVersions(String componentVersions return componentVersions; } + /** + * Load properties into a properties map + * + * @param properties The unparsed properties to load + * @return The loaded properties map + * @throws AbortException + */ + private Map readProperties(String properties) throws AbortException { + Map propertiesToSet = new HashMap(); + if (properties != null && properties.length() > 0) { + for (String line : properties.split("\n")) { + String[] propDef = line.split("="); + + if (propDef.length >= 2) { + String propName = propDef[0].trim(); + String propVal = propDef[1].trim(); + propertiesToSet.put(propName, propVal); + } + else { + throw new AbortException("Missing property delimiter '=' in property definition '" + line + "'"); + } + } + } + return propertiesToSet; + } + /** * Check the result of an application process * diff --git a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/GlobalConfig.java b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/GlobalConfig.java index e744c05..9b06aea 100644 --- a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/GlobalConfig.java +++ b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/GlobalConfig.java @@ -1,10 +1,10 @@ /** - * © Copyright IBM Corporation 2017. + * (c) Copyright IBM Corporation 2017. * This is licensed under the following license. * The Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) * U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ - + package com.urbancode.jenkins.plugins.ucdeploy; import hudson.Extension; @@ -16,6 +16,7 @@ import hudson.util.FormFieldValidator; import java.io.IOException; +import java.util.Arrays; import java.util.Iterator; import java.util.Map; @@ -24,6 +25,7 @@ import jenkins.model.Jenkins; import net.sf.json.JSONObject; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -34,6 +36,8 @@ * */ public class GlobalConfig extends JobProperty> { + + /** * {@inheritDoc} * @@ -73,6 +77,11 @@ public UCDeploySite[] getSites() { return sites.toArray(new UCDeploySite[size]); } + @DataBoundSetter + public void setSites(UCDeploySite[] sitesArray){ + sites.replaceBy(Arrays.asList(sitesArray)); + } + /** * Replace sites with user defined sites * @@ -88,6 +97,7 @@ public boolean configure(StaplerRequest req, JSONObject formData) throws FormExc return super.configure(req, formData); } + /** * {@inheritDoc} * @@ -117,14 +127,13 @@ public void doTestConnection( @QueryParameter("url") final String url, @QueryParameter("user") final String user, @QueryParameter("password") final String password, - @QueryParameter("adminUser") final boolean adminUser, @QueryParameter("trustAllCerts") final boolean trustAllCerts) throws IOException, ServletException { new FormFieldValidator(req, rsp, true) { @Override protected void check() throws IOException, ServletException { try { - UCDeploySite site = new UCDeploySite(null, url, user, password, adminUser, trustAllCerts); + UCDeploySite site = new UCDeploySite(null, url, user, password, trustAllCerts); site.verifyConnection(); ok("Success"); } diff --git a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/ProcessHelper.java b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/ProcessHelper.java index b7da892..9437af1 100644 --- a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/ProcessHelper.java +++ b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/ProcessHelper.java @@ -1,5 +1,5 @@ /** - * © Copyright IBM Corporation 2017. + * (c) Copyright IBM Corporation 2017. * This is licensed under the following license. * The Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) * U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. diff --git a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/SystemHelper.java b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/SystemHelper.java deleted file mode 100644 index 3173e29..0000000 --- a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/SystemHelper.java +++ /dev/null @@ -1,51 +0,0 @@ -/** - * © Copyright IBM Corporation 2017. - * This is licensed under the following license. - * The Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. - */ - -package com.urbancode.jenkins.plugins.ucdeploy; - -import hudson.AbortException; -import hudson.model.TaskListener; - -import java.io.IOException; -import java.net.URI; - -import org.apache.http.impl.client.DefaultHttpClient; - -import org.codehaus.jettison.json.JSONException; -import org.codehaus.jettison.json.JSONObject; - -import com.urbancode.ud.client.SystemClient; - -/** - * This class allows use of the UrbanCode Deploy REST client - * to make system related REST calls - */ -public class SystemHelper { - private SystemClient sysClient; - - public SystemHelper(URI ucdUrl, DefaultHttpClient httpClient, TaskListener listener) { - sysClient = new SystemClient(ucdUrl, httpClient); - } - - public boolean isMaintenanceEnabled() throws AbortException { - boolean maintenanceEnabled; - - try { - JSONObject systemConfig = sysClient.getSystemConfiguration(); - maintenanceEnabled = systemConfig.getBoolean("enableMaintenanceMode"); - } - catch (IOException ex) { - throw new AbortException("Invalid http response code returned when acquiring UCD system configuration:" - + ex.getMessage()); - } - catch (JSONException ex) { - throw new AbortException("Failed to acquire UCD system configuration: " + ex.getMessage()); - } - - return maintenanceEnabled; - } -} diff --git a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/UCDeployPublisher.java b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/UCDeployPublisher.java index 8dbec31..9e1b82d 100644 --- a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/UCDeployPublisher.java +++ b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/UCDeployPublisher.java @@ -1,10 +1,10 @@ /** - * © Copyright IBM Corporation 2017. + * (c) Copyright IBM Corporation 2017. * This is licensed under the following license. * The Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) * U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ - + package com.urbancode.jenkins.plugins.ucdeploy; import org.apache.http.impl.client.DefaultHttpClient; @@ -34,8 +34,10 @@ import net.sf.json.JSONObject; +import org.codehaus.jettison.json.JSONException; import org.jenkinsci.remoting.RoleChecker; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.StaplerRequest; import com.urbancode.jenkins.plugins.ucdeploy.ComponentHelper.CreateComponentBlock; @@ -46,7 +48,6 @@ import com.urbancode.jenkins.plugins.ucdeploy.DeployHelper; import com.urbancode.jenkins.plugins.ucdeploy.DeployHelper.DeployBlock; import com.urbancode.jenkins.plugins.ucdeploy.DeployHelper.CreateSnapshotBlock; -import com.urbancode.jenkins.plugins.ucdeploy.SystemHelper; import com.urbancode.jenkins.plugins.ucdeploy.VersionHelper; import com.urbancode.jenkins.plugins.ucdeploy.VersionHelper.VersionBlock; import com.urbancode.jenkins.plugins.ucdeploy.UCDeployPublisher.UserBlock; @@ -103,7 +104,7 @@ public UserBlock getAltUser() { } public Boolean altUserChecked() { - if (getAltUser() != null) { + if (altUser != null) { return true; } @@ -112,10 +113,9 @@ public Boolean altUserChecked() { public String getAltUsername() { String altUsername = ""; - String value = getAltUser().getAltUsername(); - if (value != null) { - altUsername = value; + if (altUser != null) { + altUsername = altUser.getAltUsername(); } return altUsername; @@ -123,25 +123,20 @@ public String getAltUsername() { public Secret getAltPassword() { Secret altPassword = Secret.fromString(""); - Secret value = getAltUser().getAltPassword(); - if (value != null) { - altPassword = value; + if (altUser != null) { + altPassword = altUser.getAltPassword(); } return altPassword; } - public boolean isAltUserAdmin() { - return getAltUser().isAdminUser(); - } - public VersionBlock getComponent() { return component; } public Boolean componentChecked() { - if (getComponent() != null) { + if (component != null) { return true; } @@ -150,17 +145,21 @@ public Boolean componentChecked() { public String getComponentName() { String componentName = ""; - String value = getComponent().getComponentName(); - if (value != null) { - componentName = value; + if (component != null) { + componentName = component.getComponentName(); } return componentName; } public CreateComponentBlock getCreateComponent() { - return getComponent().getCreateComponentBlock(); + if (component != null) { + return component.getCreateComponent(); + } + else { + return null; + } } public Boolean createComponentChecked() { @@ -173,10 +172,9 @@ public Boolean createComponentChecked() { public String getComponentTemplate() { String componentTemplate = ""; - String value = getCreateComponent().getComponentTemplate(); - if (value != null) { - componentTemplate = value; + if (getCreateComponent() != null) { + componentTemplate = getCreateComponent().getComponentTemplate(); } return componentTemplate; @@ -184,25 +182,28 @@ public String getComponentTemplate() { public String getComponentApplication() { String componentApplication = ""; - String value = getCreateComponent().getComponentApplication(); - if (value != null) { - componentApplication = value; + if (getCreateComponent() != null) { + componentApplication = getCreateComponent().getComponentApplication(); } return componentApplication; } public DeliveryBlock getDelivery() { - return getComponent().getDeliveryBlock(); + if (component != null) { + return component.getDelivery(); + } + else { + return null; + } } public String getDeliveryType() { String deliveryType = ""; - String value = getDelivery().getDeliveryType().name(); - if (value != null) { - deliveryType = value; + if (getDelivery() != null) { + deliveryType = getDelivery().getDeliveryType().name(); } return deliveryType; @@ -210,10 +211,9 @@ public String getDeliveryType() { public String getPushVersion() { String pushVersion = ""; - String value = ((Push)getDelivery()).getPushVersion(); - if (value != null) { - pushVersion = value; + if (getDelivery() != null && getDelivery() instanceof Push) { + pushVersion = ((Push)getDelivery()).getPushVersion(); } return pushVersion; @@ -221,10 +221,9 @@ public String getPushVersion() { public String getBaseDir() { String baseDir = ""; - String value = ((Push)getDelivery()).getBaseDir(); - if (value != null) { - baseDir = value; + if (getDelivery() != null && getDelivery() instanceof Push) { + baseDir = ((Push)getDelivery()).getBaseDir(); } return baseDir; @@ -232,10 +231,9 @@ public String getBaseDir() { public String getFileIncludePatterns() { String fileIncludePatterns = ""; - String value = ((Push)getDelivery()).getFileIncludePatterns(); - if (value != null) { - fileIncludePatterns = value; + if (getDelivery() != null && getDelivery() instanceof Push) { + fileIncludePatterns = ((Push)getDelivery()).getFileIncludePatterns(); } return fileIncludePatterns; @@ -243,10 +241,9 @@ public String getFileIncludePatterns() { public String getFileExcludePatterns() { String fileExcludePatterns = ""; - String value = ((Push)getDelivery()).getFileExcludePatterns(); - if (value != null) { - fileExcludePatterns = value; + if (getDelivery() != null && getDelivery() instanceof Push) { + fileExcludePatterns = ((Push)getDelivery()).getFileExcludePatterns(); } return fileExcludePatterns; @@ -254,10 +251,9 @@ public String getFileExcludePatterns() { public String getPushProperties() { String pushProperties = ""; - String value = ((Push)getDelivery()).getPushProperties(); - if (value != null) { - pushProperties = value; + if (getDelivery() != null && getDelivery() instanceof Push) { + pushProperties = ((Push)getDelivery()).getPushProperties(); } return pushProperties; @@ -265,30 +261,27 @@ public String getPushProperties() { public String getPushDescription() { String pushDescription = ""; - String value = ((Push)getDelivery()).getPushDescription(); - if (value != null) { - pushDescription = value; + if (getDelivery() != null && getDelivery() instanceof Push) { + pushDescription = ((Push)getDelivery()).getPushDescription(); } return pushDescription; } public Boolean getPushIncremental() { - if (((Push)getDelivery()).getPushIncremental() != null) { - return false; - } - else { + if (getDelivery() != null && getDelivery() instanceof Push) { return ((Push)getDelivery()).getPushIncremental(); } + + return false; } public String getPullProperties() { String pullProperties = ""; - String value = ((Pull)getDelivery()).getPullProperties(); - if (value != null) { - pullProperties = value; + if (getDelivery() != null && getDelivery() instanceof Pull) { + pullProperties = ((Pull)getDelivery()).getPullProperties(); } return pullProperties; @@ -296,10 +289,9 @@ public String getPullProperties() { public String getpullSourceType() { String pullSourceType = ""; - String value = ((Pull)getDelivery()).getPullSourceType(); - if (value != null) { - pullSourceType = value; + if (getDelivery() != null && getDelivery() instanceof Pull) { + pullSourceType = ((Pull)getDelivery()).getPullSourceType(); } return pullSourceType; @@ -307,22 +299,20 @@ public String getpullSourceType() { public String getPullSourceProperties() { String pullSourceProperties = ""; - String value = ((Pull)getDelivery()).getPullSourceProperties(); - if (value != null) { - pullSourceProperties = value; + if (getDelivery() != null && getDelivery() instanceof Pull) { + pullSourceProperties = ((Pull)getDelivery()).getPullSourceProperties(); } return pullSourceProperties; } public Boolean getPullIncremental() { - if (((Pull)getDelivery()).getPullIncremental() == null) { - return false; - } - else { + if (getDelivery() != null && getDelivery() instanceof Pull) { return ((Pull)getDelivery()).getPullIncremental(); } + + return false; } public DeployBlock getDeploy() { @@ -330,7 +320,7 @@ public DeployBlock getDeploy() { } public Boolean deployChecked() { - if (getDeploy() != null) { + if (deploy != null) { return true; } @@ -339,10 +329,9 @@ public Boolean deployChecked() { public String getDeployApp() { String deployApp = ""; - String value = getDeploy().getDeployApp(); - if (value != null) { - deployApp = value; + if (deploy != null) { + deployApp = deploy.getDeployApp(); } return deployApp; @@ -350,10 +339,9 @@ public String getDeployApp() { public String getDeployEnv() { String deployEnv = ""; - String value = getDeploy().getDeployEnv(); - if (value != null) { - deployEnv = value; + if (deploy != null) { + deployEnv = deploy.getDeployEnv(); } return deployEnv; @@ -361,17 +349,24 @@ public String getDeployEnv() { public String getDeployProc() { String deployProc = ""; - String value = getDeploy().getDeployProc(); - if (value != null) { - deployProc = value; + if (deploy != null) { + deployProc = deploy.getDeployProc(); } return deployProc; } + public Boolean getSkipWait() { + if (deploy != null) { + return deploy.getSkipWait(); + } + + return false; + } + public CreateProcessBlock getCreateProcess() { - return getDeploy().getCreateProcessBlock(); + return deploy.getCreateProcess(); } public Boolean createProcessChecked() { @@ -385,17 +380,16 @@ public Boolean createProcessChecked() { public String getProcessComponent() { String processComponent = ""; - String value = getCreateProcess().getProcessComponent(); - if (value != null) { - processComponent = value; + if (getCreateProcess() != null) { + processComponent = getCreateProcess().getProcessComponent(); } return processComponent; } public CreateSnapshotBlock getCreateSnapshot() { - return getDeploy().getCreateSnapshotBlock(); + return deploy.getCreateSnapshot(); } public Boolean createSnapshotChecked() { @@ -409,28 +403,63 @@ public Boolean createSnapshotChecked() { public String getSnapshotName() { String snapshotName = ""; - String value = getCreateSnapshot().getSnapshotName(); - if (value != null) { - snapshotName = value; + if (getCreateSnapshot() != null) { + snapshotName = getCreateSnapshot().getSnapshotName(); } return snapshotName; } + public Boolean getDeployWithSnapshot() { + if (getCreateSnapshot() != null) { + return ((getCreateSnapshot()).getDeployWithSnapshot()); + } + + return false; + } + + public Boolean getIncludeOnlyDeployVersions() { + if (getCreateSnapshot() != null) { + return ((getCreateSnapshot()).getIncludeOnlyDeployVersions()); + } + else { + return false; + } + } + public String getDeployVersions() { String deployVersions = ""; - String value = getDeploy().getDeployVersions(); - if (value != null) { - deployVersions = value; + if (deploy != null) { + deployVersions = deploy.getDeployVersions(); } return deployVersions; } + public String getDeployReqProps() { + String deployReqProps = ""; + + if (deploy != null) { + deployReqProps = deploy.getDeployReqProps(); + } + + return deployReqProps; + } + + public String getDeployDesc() { + String deployDesc = ""; + + if (deploy != null) { + deployDesc = deploy.getDeployDesc(); + } + + return deployDesc; + } + public Boolean getDeployOnlyChanged() { - if (getDeploy().getDeployOnlyChanged() == null) { + if (deploy.getDeployOnlyChanged() == null) { return false; } else { @@ -481,7 +510,6 @@ public void perform(final Run build, FilePath workspace, Launcher launcher UCDeploySite udSite = getSite(); DefaultHttpClient udClient; // not serializable - boolean adminUser = false; if (altUserChecked()) { if (getAltUsername().equals("")) { @@ -492,22 +520,9 @@ public void perform(final Run build, FilePath workspace, Launcher launcher listener.getLogger().println("Running job as alternative user '" + getAltUsername() + "'."); udClient = udSite.getTempClient(getAltUsername(), getAltPassword()); - adminUser = isAltUserAdmin(); } else { udClient = udSite.getClient(); - adminUser = udSite.isAdminUser(); - } - - if (adminUser) { - SystemHelper sysHelper = new SystemHelper(udSite.getUri(), udClient, listener); - - listener.getLogger().println("Administrative user specified. Checking if server is running in " - + "maintenance mode."); - if (sysHelper.isMaintenanceEnabled()) { - throw new AbortException("The UrbanCode Deploy server is running in maintenance mode " - + "and no processes may be run."); - } } EnvVars envVars = build.getEnvironment(listener); @@ -528,20 +543,28 @@ public void perform(final Run build, FilePath workspace, Launcher launcher if (deployChecked()) { DeployHelper deployHelper = new DeployHelper(udSite.getUri(), udClient, listener, envVars); - deployHelper.deployVersion(getDeploy()); + + /* Throw AbortException so that Jenkins will mark job as faulty */ + try { + deployHelper.runDeployment(getDeploy()); + } + catch (IOException ex) { + throw new AbortException("Deployment has failed due to IOException " + ex.getMessage()); + } + catch (JSONException ex) { + throw new AbortException("Deployment has failed due to JSONException " + ex.getMessage()); + } } } public static class UserBlock implements Serializable { private String altUsername; private Secret altPassword; - private boolean adminUser; @DataBoundConstructor - public UserBlock(String altUsername, Secret altPassword, boolean adminUser) { + public UserBlock(String altUsername, Secret altPassword) { this.altUsername = altUsername; this.altPassword = altPassword; - this.adminUser = adminUser; } public String getAltUsername() { @@ -559,14 +582,6 @@ public Secret getAltPassword() { public void setAltPassword(Secret altPassword) { this.altPassword = altPassword; } - - public boolean isAdminUser() { - return adminUser; - } - - public void setAdminUser(boolean adminUser) { - this.adminUser = adminUser; - } } /** @@ -661,6 +676,11 @@ public UCDeploySite[] getSites() { return GLOBALDESCRIPTOR.getSites(); } + @DataBoundSetter + public void setSites(UCDeploySite[] sitesArray) { + GLOBALDESCRIPTOR.setSites(sitesArray); + } + /** * Bind data fields to user defined values {@inheritDoc} * diff --git a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/UCDeploySite.java b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/UCDeploySite.java index f94df87..0f6b0be 100644 --- a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/UCDeploySite.java +++ b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/UCDeploySite.java @@ -1,10 +1,10 @@ /** - * © Copyright IBM Corporation 2017. + * (c) Copyright IBM Corporation 2017. * This is licensed under the following license. * The Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) * U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ - + package com.urbancode.jenkins.plugins.ucdeploy; import com.urbancode.ud.client.UDRestClient; @@ -25,6 +25,7 @@ import org.apache.http.HttpResponse; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; /** * This class is used to configure individual sites which are @@ -44,8 +45,6 @@ public class UCDeploySite implements Serializable { private Secret password; - private boolean adminUser; - private boolean trustAllCerts; transient private DefaultHttpClient client; @@ -64,7 +63,6 @@ public UCDeploySite() { * @param url the url of the UrbanDeploy instance * @param user * @param password - * @param adminUser * @param trustAllCerts */ public UCDeploySite( @@ -72,14 +70,12 @@ public UCDeploySite( String url, String user, Secret password, - boolean adminUser, boolean trustAllCerts) { this.profileName = profileName; this.url = url; this.user = user; this.password = password; - this.adminUser = adminUser; this.trustAllCerts = trustAllCerts; client = UDRestClient.createHttpClient(user, password.toString(), trustAllCerts); } @@ -91,7 +87,6 @@ public UCDeploySite( * @param url * @param user * @param password - * @param adminUser * @param trustAllCerts */ @DataBoundConstructor @@ -100,10 +95,9 @@ public UCDeploySite( String url, String user, String password, - boolean adminUser, boolean trustAllCerts) { - this(profileName, url, user, Secret.fromString(password), adminUser, trustAllCerts); + this(profileName, url, user, Secret.fromString(password), trustAllCerts); } public DefaultHttpClient getClient() { @@ -145,6 +139,7 @@ public String getProfileName() { * @param profileName * the new profile name */ + @DataBoundSetter public void setProfileName(String profileName) { this.profileName = profileName; } @@ -164,6 +159,7 @@ public String getUrl() { * @param url * the new url */ + @DataBoundSetter public void setUrl(String url) { this.url = url; if (this.url != null) { @@ -202,6 +198,7 @@ public String getUser() { * @param username * the new username */ + @DataBoundSetter public void setUser(String user) { this.user = user; } @@ -221,28 +218,11 @@ public Secret getPassword() { * @param password * the new password */ + @DataBoundSetter public void setPassword(Secret password) { this.password = password; } - /** - * Gets adminUser - * - * @return if the user set on this client has administrative credentials - */ - public boolean isAdminUser() { - return adminUser; - } - - /** - * Sets adminUser to set if this user has administrative credentials - * - * @param adminUser - */ - public void setAdminUser(boolean adminUser) { - this.adminUser = adminUser; - } - /** * Gets trustAllCerts * @@ -257,6 +237,7 @@ public boolean isTrustAllCerts() { * * @param trustAllCerts */ + @DataBoundSetter public void setTrustAllCerts(boolean trustAllCerts) { this.trustAllCerts = trustAllCerts; } diff --git a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/VersionHelper.java b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/VersionHelper.java index 92a1827..c4bb2b7 100644 --- a/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/VersionHelper.java +++ b/src/main/java/com/urbancode/jenkins/plugins/ucdeploy/VersionHelper.java @@ -1,15 +1,20 @@ /** - * © Copyright IBM Corporation 2017. + * (c) Copyright IBM Corporation 2017. * This is licensed under the following license. * The Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) * U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ - + package com.urbancode.jenkins.plugins.ucdeploy; import hudson.AbortException; import hudson.EnvVars; import hudson.model.TaskListener; +import hudson.slaves.EnvironmentVariablesNodeProperty; +import hudson.slaves.NodeProperty; +import hudson.slaves.NodePropertyDescriptor; +import hudson.util.DescribableList; +import jenkins.model.Jenkins; import java.io.File; import java.io.IOException; @@ -91,12 +96,12 @@ public String getComponentTag() { } } - public CreateComponentBlock getCreateComponentBlock() { + public CreateComponentBlock getCreateComponent() { return createComponent; } public Boolean createComponentChecked() { - if (getCreateComponentBlock() == null) { + if (getCreateComponent() == null) { return false; } else { @@ -104,7 +109,7 @@ public Boolean createComponentChecked() { } } - public DeliveryBlock getDeliveryBlock() { + public DeliveryBlock getDelivery() { return delivery; } } @@ -130,8 +135,8 @@ public void createVersion(VersionBlock versionBlock, String linkName, String lin // create component if (versionBlock.createComponentChecked()) { componentHelper.createComponent(componentName, - versionBlock.getCreateComponentBlock(), - versionBlock.getDeliveryBlock()); + versionBlock.getCreateComponent(), + versionBlock.getDelivery()); } // tag component @@ -140,8 +145,8 @@ public void createVersion(VersionBlock versionBlock, String linkName, String lin } // create version - if (versionBlock.getDeliveryBlock().getDeliveryType() == DeliveryBlock.DeliveryType.Push) { - Push pushBlock = (Push)versionBlock.getDeliveryBlock(); + if (versionBlock.getDelivery().getDeliveryType() == DeliveryBlock.DeliveryType.Push) { + Push pushBlock = (Push)versionBlock.getDelivery(); String version = envVars.expand(pushBlock.getPushVersion()); listener.getLogger().println("Creating new component version '" + version + "' on component '" + componentName + "'"); @@ -160,6 +165,13 @@ public void createVersion(VersionBlock versionBlock, String linkName, String lin } listener.getLogger().println("Successfully created component version with UUID '" + versionId.toString() + "'"); + try { + putEnvVar(componentName + "_VersionId", versionId.toString()); + } + catch (Exception ex) { + listener.getLogger().println("[Warning] Failed to set version ID as environment variable."); + } + // upload files listener.getLogger().println("Uploading files to version '" + version + "' on component '" + componentName + "'"); uploadVersionFiles(envVars.expand(pushBlock.getBaseDir()), @@ -186,8 +198,8 @@ public void createVersion(VersionBlock versionBlock, String linkName, String lin } // import version - else if (versionBlock.getDeliveryBlock().getDeliveryType() == DeliveryBlock.DeliveryType.Pull) { - Pull pullBlock = (Pull)versionBlock.getDeliveryBlock(); + else if (versionBlock.getDelivery().getDeliveryType() == DeliveryBlock.DeliveryType.Pull) { + Pull pullBlock = (Pull)versionBlock.getDelivery(); Map mappedProperties = DeliveryBlock.mapProperties(envVars.expand(pullBlock.getPullProperties())); listener.getLogger().println("Using runtime properties " + mappedProperties); @@ -206,7 +218,7 @@ else if (versionBlock.getDeliveryBlock().getDeliveryType() == DeliveryBlock.Deli // invalid type else { - throw new AbortException("Invalid Delivery Type: " + versionBlock.getDeliveryBlock().getDeliveryType()); + throw new AbortException("Invalid Delivery Type: " + versionBlock.getDelivery().getDeliveryType()); } } @@ -235,6 +247,10 @@ public void uploadVersionFiles( if (!base.exists()) { throw new AbortException("Base artifact directory " + base.getAbsolutePath() + " does not exist"); } + + if(base.list().length==0) { + throw new AbortException("Base artifact directory " + base.getAbsolutePath() + " does not contain any files to upload. Please place files."); + } try { verClient.addVersionFiles(component, @@ -251,6 +267,35 @@ public void uploadVersionFiles( } } + /** + * Set environment variable. + * @param key + * @param value + * @throws IOException + */ + private void putEnvVar(String key, String value) throws IOException { + key = key.replaceAll(" ", "_"); + listener.getLogger().println("Setting environment variable " + key + "."); + Jenkins jenkins = Jenkins.getInstance(); + DescribableList, NodePropertyDescriptor> globalNodeProperties = + jenkins.getGlobalNodeProperties(); + List envVarsNodePropertyList = + globalNodeProperties.getAll(hudson.slaves.EnvironmentVariablesNodeProperty.class); + + EnvironmentVariablesNodeProperty newEnvVarsNodeProperty = null; + EnvVars envVars = null; + + if (envVarsNodePropertyList == null || envVarsNodePropertyList.isEmpty()) { + newEnvVarsNodeProperty = new hudson.slaves.EnvironmentVariablesNodeProperty(); + globalNodeProperties.add(newEnvVarsNodeProperty); + envVars = newEnvVarsNodeProperty.getEnvVars(); + } else { + envVars = envVarsNodePropertyList.get(0).getEnvVars(); + } + envVars.put(key, value); + jenkins.save(); + } + /** * Split a string of filenames by newline and remove empty/null entries * diff --git a/src/main/resources/com/urbancode/jenkins/plugins/ucdeploy/GlobalConfig/global.jelly b/src/main/resources/com/urbancode/jenkins/plugins/ucdeploy/GlobalConfig/global.jelly index fe307c1..bf21641 100644 --- a/src/main/resources/com/urbancode/jenkins/plugins/ucdeploy/GlobalConfig/global.jelly +++ b/src/main/resources/com/urbancode/jenkins/plugins/ucdeploy/GlobalConfig/global.jelly @@ -18,9 +18,6 @@ - - - diff --git a/src/main/resources/com/urbancode/jenkins/plugins/ucdeploy/UCDeployPublisher/config.jelly b/src/main/resources/com/urbancode/jenkins/plugins/ucdeploy/UCDeployPublisher/config.jelly index d87cb0d..3736f67 100644 --- a/src/main/resources/com/urbancode/jenkins/plugins/ucdeploy/UCDeployPublisher/config.jelly +++ b/src/main/resources/com/urbancode/jenkins/plugins/ucdeploy/UCDeployPublisher/config.jelly @@ -17,15 +17,12 @@ checked="${instance.altUserChecked()}"> - + - + - - -
@@ -47,13 +44,13 @@ checked="${instance.createComponentChecked()}"> - - @@ -124,6 +121,9 @@ + + + + + + + + +
+ + + + + + @@ -159,4 +171,4 @@ - \ No newline at end of file + diff --git a/src/main/webapp/deploy/desc.html b/src/main/webapp/deploy/desc.html new file mode 100644 index 0000000..0628c69 --- /dev/null +++ b/src/main/webapp/deploy/desc.html @@ -0,0 +1,3 @@ +
+ Give a description or explanation for the deployment process and snapshot. +
diff --git a/src/main/webapp/deploy/reqprops.html b/src/main/webapp/deploy/reqprops.html new file mode 100644 index 0000000..58cec68 --- /dev/null +++ b/src/main/webapp/deploy/reqprops.html @@ -0,0 +1,3 @@ +
+ A new line separated list of application request properties. Each property should be of the form name=value. +
diff --git a/src/main/webapp/deploy/skipwait.html b/src/main/webapp/deploy/skipwait.html new file mode 100644 index 0000000..f6841b8 --- /dev/null +++ b/src/main/webapp/deploy/skipwait.html @@ -0,0 +1,4 @@ +
+ Check this box to skip waiting for UrbanCode deploy to finish the deployment. + If this box is checked, the plugin will kick off the deployment and return immediately. +
\ No newline at end of file diff --git a/src/main/webapp/deploy/snapshot/deploy-snapshot-for-deploy-versions-only.html b/src/main/webapp/deploy/snapshot/deploy-snapshot-for-deploy-versions-only.html new file mode 100644 index 0000000..587da7e --- /dev/null +++ b/src/main/webapp/deploy/snapshot/deploy-snapshot-for-deploy-versions-only.html @@ -0,0 +1,4 @@ +
+ Select to deploy with your newly created snapshot. When this option is selected only component + versions specified in the 'Snapshot/Component Versions' field will be added to the new snapshot. +
\ No newline at end of file diff --git a/src/main/webapp/deploy/snapshot/deploy-snapshot.html b/src/main/webapp/deploy/snapshot/deploy-snapshot.html new file mode 100644 index 0000000..3150794 --- /dev/null +++ b/src/main/webapp/deploy/snapshot/deploy-snapshot.html @@ -0,0 +1,5 @@ +
+ Select to deploy with your newly created snapshot. When this option is selected any component + versions specified in the 'Snapshot/Component Versions' field will be added to the + new snapshot instead of being used directly for the deployment. +
\ No newline at end of file diff --git a/src/main/webapp/deploy/snapshot/help.html b/src/main/webapp/deploy/snapshot/help.html index 6534838..21dd0cc 100644 --- a/src/main/webapp/deploy/snapshot/help.html +++ b/src/main/webapp/deploy/snapshot/help.html @@ -1,3 +1,5 @@
- Select to create a snapshot of the deployment environment in UrbanCode Deploy upon successful deployment. + Select to create a snapshot of the deployment environment in UrbanCode Deploy + upon successful deployment. Selecting the 'Deploy With Snapshot' checkbox will cause + the snapshot to be created preemptively and used for the deployment.
\ No newline at end of file diff --git a/src/main/webapp/deploy/versions.html b/src/main/webapp/deploy/versions.html index cf9e596..e51a30f 100644 --- a/src/main/webapp/deploy/versions.html +++ b/src/main/webapp/deploy/versions.html @@ -8,7 +8,9 @@
  • SNAPSHOT: - Specify the name of a single SNAPSHOT to deploy. + Specify the name of a single SNAPSHOT to deploy. This snapshot will be ignored if the + 'Deploy With Snapshot' option is selected in the 'Create Snapshot of Build Environment'. + Indicate a Snapshot by prepending the word SNAPSHOT and an equals to the Snapshot name. Example- SNAPSHOT=Name
  • - \ No newline at end of file +