Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implement workaround for incompatible change in cloud foundry API #343

Merged
merged 9 commits into from
Oct 17, 2018
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions documentation/docs/steps/cloudFoundryDeploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ Deployment can be done
- cfOrg
- cfSpace

!!! note
Due to [an incompatible change](https://github.com/cloudfoundry/cli/issues/1445) in the Cloud Foundry CLI, multiple buildpacks are not supported by this step.
If your `application` contains a list of `buildpacks` instead a single `buildpack`, this will be automatically re-written by the step.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only in case you are using the blue green deployment


* `deployTool` defines the tool which should be used for deployment.
* `deployType` defines the type of deployment, either `standard` deployment which results in a system downtime or a zero-downtime `blue-green` deployment.
* `dockerImage` defines the Docker image containing the deployment tools (like cf cli, ...) and `dockerWorkspace` defines the home directory of the default user of the `dockerImage`
Expand Down Expand Up @@ -106,7 +110,11 @@ The following parameters can also be specified as step/stage/general parameters
## Example

```groovy
artifactSetVersion script: this, buildTool: 'maven'
cloudFoundryDeploy(
script: script,
deployType: 'blue-green',
cloudFoundry: [apiEndpoint: 'https://test.server.com', appName:'cfAppName', credentialsId: 'cfCredentialsId', manifest: 'cfManifest', org: 'cfOrg', space: 'cfSpace'],
deployTool: 'cf_native'
)
```


26 changes: 26 additions & 0 deletions src/com/sap/piper/CfManifestUtils.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.sap.piper

import com.cloudbees.groovy.cps.NonCPS

class CfManifestUtils {
@NonCPS
static Map transform(Map manifest) {
if (manifest.applications[0].buildpacks) {
manifest['applications'].each { Map application ->
def buildpacks = application['buildpacks']
if (buildpacks) {
if (buildpacks instanceof List) {
if (buildpacks.size > 1) {
throw new RuntimeException('More than one Cloud Foundry Buildpack is not supported. Please check your manifest.yaml file.')
}
application['buildpack'] = buildpacks[0]
application.remove('buildpacks')
} else {
throw new RuntimeException('"buildpacks" in manifest.yaml is not a list. Please check your manifest.yaml file.')
}
}
}
}
return manifest
}
}
25 changes: 24 additions & 1 deletion test/groovy/CloudFoundryDeployTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ class CloudFoundryDeployTest extends BasePiperTest {

@Test
void testCfNativeWithAppName() {
jryr.registerYaml('test.yml', "applications: [[name: 'manifestAppName']]")
helper.registerAllowedMethod('writeYaml', [Map], { Map parameters ->
generatedFile = parameters.file
data = parameters.data
})
jsr.step.cloudFoundryDeploy([
script: nullScript,
juStabUtils: utils,
Expand All @@ -125,6 +130,11 @@ class CloudFoundryDeployTest extends BasePiperTest {

@Test
void testCfNativeWithAppNameCustomApi() {
jryr.registerYaml('test.yml', "applications: [[name: 'manifestAppName']]")
helper.registerAllowedMethod('writeYaml', [Map], { Map parameters ->
generatedFile = parameters.file
data = parameters.data
})
jsr.step.cloudFoundryDeploy([
script: nullScript,
juStabUtils: utils,
Expand All @@ -142,6 +152,11 @@ class CloudFoundryDeployTest extends BasePiperTest {

@Test
void testCfNativeWithAppNameCompatible() {
jryr.registerYaml('test.yml', "applications: [[name: 'manifestAppName']]")
helper.registerAllowedMethod('writeYaml', [Map], { Map parameters ->
generatedFile = parameters.file
data = parameters.data
})
jsr.step.cloudFoundryDeploy([
script: nullScript,
juStabUtils: utils,
Expand All @@ -165,7 +180,11 @@ class CloudFoundryDeployTest extends BasePiperTest {
@Test
void testCfNativeAppNameFromManifest() {
helper.registerAllowedMethod('fileExists', [String.class], { s -> return true })
jryr.registerYaml('test.yml', "[applications: [[name: 'manifestAppName']]]")
jryr.registerYaml('test.yml', "applications: [[name: 'manifestAppName']]")
helper.registerAllowedMethod('writeYaml', [Map], { Map parameters ->
generatedFile = parameters.file
data = parameters.data
})

jsr.step.cloudFoundryDeploy([
script: nullScript,
Expand All @@ -185,6 +204,10 @@ class CloudFoundryDeployTest extends BasePiperTest {
void testCfNativeWithoutAppName() {
helper.registerAllowedMethod('fileExists', [String.class], { s -> return true })
jryr.registerYaml('test.yml', "applications: [[]]")
helper.registerAllowedMethod('writeYaml', [Map], { Map parameters ->
generatedFile = parameters.file
data = parameters.data
})
thrown.expect(hudson.AbortException)
thrown.expectMessage('[cloudFoundryDeploy] ERROR: No appName available in manifest test.yml.')

Expand Down
30 changes: 30 additions & 0 deletions test/groovy/com/sap/piper/CfManifestUtilsTest.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.sap.piper

import org.junit.Test

import static org.junit.Assert.*

class CfManifestUtilsTest {

@Test
void testManifestTransform() {
Map testFixture = [applications: [[buildpacks: ['sap_java_buildpack']]]]
Map expected = [applications: [[buildpack: 'sap_java_buildpack']]]
def actual = CfManifestUtils.transform(testFixture)
assertEquals(expected, actual)
}

@Test(expected = RuntimeException)
void testManifestTransformMultipleBuildpacks() {
Map testFixture = [applications: [[buildpacks: ['sap_java_buildpack', 'another_buildpack']]]]
CfManifestUtils.transform(testFixture)
}

@Test
void testManifestTransformShouldNotChange() {
Map testFixture = [applications: [[buildpack: 'sap_java_buildpack']]]
Map expected = [applications: [[buildpack: 'sap_java_buildpack']]]
def actual = CfManifestUtils.transform(testFixture)
assertEquals(expected, actual)
}
}
19 changes: 18 additions & 1 deletion vars/cloudFoundryDeploy.groovy
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import com.sap.piper.Utils
import com.sap.piper.ConfigurationHelper
import com.sap.piper.CfManifestUtils

import groovy.transform.Field

Expand Down Expand Up @@ -112,6 +113,7 @@ def deployCfNative (config) {
def deployCommand = 'push'
if (config.deployType == 'blue-green') {
deployCommand = 'blue-green-deploy'
handleLegacyCfManifest(config)
} else {
config.smokeTest = ''
}
Expand All @@ -129,7 +131,7 @@ def deployCfNative (config) {
}

sh """#!/bin/bash
set +x
set +x
export HOME=${config.dockerWorkspace}
cf login -u \"${username}\" -p '${password}' -a ${config.cloudFoundry.apiEndpoint} -o \"${config.cloudFoundry.org}\" -s \"${config.cloudFoundry.space}\"
cf plugins
Expand Down Expand Up @@ -166,3 +168,18 @@ def deployMta (config) {
sh "cf logout"
}
}

def handleLegacyCfManifest(config) {
def manifest = readYaml file: config.cloudFoundry.manifest
String originalManifest = manifest.toString()
manifest = CfManifestUtils.transform(manifest)
String transformedManifest = manifest.toString()
if (originalManifest != transformedManifest) {
echo """The file ${config.cloudFoundry.manifest} is not compatible with the Cloud Foundry blue-green deployment plugin. Re-writing inline.
See this issue if you are interested in the background: https://github.com/cloudfoundry/cli/issues/1445.\n
Original manifest file content: $originalManifest\n
Transformed manifest file content: $transformedManifest"""
sh "rm ${config.cloudFoundry.manifest}"
writeYaml file: config.cloudFoundry.manifest, data: manifest
}
}