Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Configuring Bamboo for Salesforce Integration

DZone's Guide to

Configuring Bamboo for Salesforce Integration

A continuation of Zone Leader John Vester's article series on incorporating Salesforce into your DevOps processes.

· DevOps Zone
Free Resource

Learn more about how CareerBuilder was able to resolve customer issues 5x faster by using Scalyr, the fastest log management tool on the market. 

In my last article, the steps necessary to configure the Force IDE for Eclipse were documented. Once in place, the plug-in was used to pull metadata from the Production Salesforce Org. The extracted code was then checked into Atlassian Stash - which is a git-based repository.

In this article, Altassian Bamboo, Apache Ant and the Force Migration Tool will be used to automate the deployment into Salesforce Org using the code checked into Stash.

Force Migration Tool Configuration

The first step is to configure the Force Migration Tool within Stash. As you may recall, the base folder name for my Salesforce repository is called sfdc. Within the sfdc folder, I created a folder called "build."  Place the following files inside the build folder:

  • ant-salesforce.jar (which is the core code for the Force Migration Tool)

  • build.properties

  • build.xml

Additionally, in order to perform deletions as part of the C/I process, create a folder within build called "unDeployCode."  Place the following files inside the unDeployCode folder:

  • destructiveChanges.xml

  • package.xml

The completed file structure should appear as shown below:

Image title

Configuring Files 

The next step is to configure some of the files created above.  Please note - the text provided below contains sample files, which may not work properly in your Org.  They are intended for illustration purposes and I certainly recommend reviewing the Force Migration Tool documentation more before putting these ideas into place.

build.properties

The first file is the build.properties file, which should be configured similar to what is listed below:

sfdc.maxPoll = 100
sfdc.pollWaitMillis = 100000

These values were the default values, which have worked well with my configuration.

build.xml

The build.xml is where the majority of the work will be configured.  For this article, I am only going to include a few Ant targets.  Otherwise, this article would become quite lengthy. 

<project name="Retrieve and Deploy SFDC metadata" default="deployEmptyCheckOnly" basedir=".." xmlns:sf="antlib:com.salesforce">
    <taskdef uri="antlib:com.salesforce"
        resource="com/salesforce/antlib.xml"
        classpath="${basedir}/build/ant-salesforce.jar"/>

    <property file="${basedir}/build/build.properties"/>
    <property environment="env"/>

    <target name="deployEmptyCheckOnly" depends="delete_unmigrateable_files">
      <echo level="info">Testing the deploy</echo>
      <sf:deploy
          checkOnly="true"
          logType="Debugonly"
          username="${sfdc.username}"
          password="${sfdc.password}"
          serverurl="${sfdc.serverurl}"
          deployRoot="${basedir}/src"
          pollWaitMillis="${sfdc.pollWaitMillis}"
          maxPoll="${sfdc.maxPoll}" 
          testLevel="NoTestRun"
          allowMissingFiles="false"
          autoUpdatePackage="false"
          rollbackOnError="true"
          ignoreWarnings="true"/>
    </target>

    <target name="deployCode" depends="delete_unmigrateable_files">
      <echo level="info">Performing the deploy (do not run tests)</echo>
      <sf:deploy
        username="${sfdc.username}"
        password="${sfdc.password}"
        serverurl="${sfdc.serverurl}"
        deployRoot="${basedir}/src"
        pollWaitMillis="${sfdc.pollWaitMillis}"
        maxPoll="${sfdc.maxPoll}"
        allowMissingFiles="false"
        autoUpdatePackage="false"
        rollbackOnError="true"
        ignoreWarnings="true"
        testLevel="NoTestRun"
        logType="Debugonly"/>
    </target>

    <target name="undeployCode">
        <echo level="info">Undeploying code</echo>
        <sf:deploy
        username="${sfdc.username}"
        password="${sfdc.password}"
        serverurl="${sfdc.serverurl}"
        maxPoll="${sfdc.maxPoll}"
        rollbackOnError="true"
        allowMissingFiles="false"
        autoUpdatePackage="false"
        ignoreWarnings="true"
        logType="Debugonly"
        purgeOnDelete="true"
        zipFile="unDeployCode.zip"/>
    </target>     

    <target name="remove_profile_references">
        <echo level="info">Removing references that cannot be migrated from all profiles</echo>
        <echo level="info">  - Social Persona</echo>
        <replaceregexp
            match="^    &lt;tabVisibilities&gt;\n        &lt;tab&gt;standard-SocialPersona&lt;/tab&gt;\n        &lt;visibility&gt;DefaultOff&lt;/visibility&gt;\n    &lt;/tabVisibilities&gt;$"
            replace=""
            flags="gm"
            byline="false">
            <fileset
            dir="${basedir}/src/profiles"
            includes="**/*.profile"
            />
        </replaceregexp>
        <echo level="info">Removing references that cannot be migrated from all objects</echo>
        <echo level="info">  - MapHighlightAction</echo>
        <replaceregexp
            match="^    &lt;actionOverrides&gt;\n        &lt;actionName&gt;MapHighlightAction&lt;/actionName&gt;\n        &lt;type&gt;Default&lt;/type&gt;\n    &lt;/actionOverrides&gt;$"
            replace=""
            flags="gm"
            byline="false">
            <fileset
            dir="${basedir}/src/objects"
            includes="**/*.object"
            />
        </replaceregexp>
        <echo level="info">Cleaning up build.xml for references that cannot be migrated</echo>
        <echo level="info">  - unfiled$public</echo>
        <replaceregexp
            match="^        &lt;members&gt;unfiled\$public&lt;/members&gt;$"
            replace=""
            flags="gm"
            byline="false">
            <fileset
            dir="${basedir}/src"
            includes="**/*.xml"
            />
        </replaceregexp>
    </target>

    <target name="delete_unmigrateable_files" depends="remove_profile_references">
        <echo level="info">Removing files that cannot be migrated</echo>
        <echo level="info">  - Applications</echo>
        <delete file="${basedir}/src/applications/standard__Work.app"/>
        <echo level="info">  - Layouts</echo>
        <delete file="${basedir}/src/layouts/FeedItem-Feed Item Layout.layout"/>
        <echo level="info">  - Settings</echo>
        <delete file="${basedir}/src/settings/PersonalJourney.settings"/>
        <echo level="info">  - Workflows</echo>
        <delete file="${basedir}/src/workflows/ExternalEventMapping.workflow"/>
    </target>

</project>

In the build.xml above, standard Ant project, task definition and property tags were created.  There are also four targets, which are noted as follows:

  • deloyEmptyCheckOnly - is used to sanity check the code being checked in.  It depends on "delete_unmigrateable_files" which is documented below. 

  • deployCode - is used to deploy code to a Salesforce Org.  It depends on "delete_unmigrateable_files" which is documented below.  This will be referenced in my next article.

  • undeployCode - is used to undeploy code from a Salesforce Org.  Since there is not a way to back-out changes successfully deployed, this file comes in handy to automatically remove elements from a target Org.  This will be referenced in my next article.

  • delete_unmigrateable_files - is used to delete files which cannot be migrated.  In the example above, the standard__Work.app is removed from the working directory so that the code is not pushed to the target Org.  The list of these files depends on your environment, but are mostly found through Google searches and attempting the migrations yourself.  It depends on "remove_profile_references" which is documented below.

  • remove_profile_references - is used to clean up elements from the profiles.  This is similar to delete_unmigrateable_file (above) and are the result of either Google searches or trial/error tests within your test deployments.

The build.xml configuration is, by far, the most complicated factor with the deployment.  This is because Salesforce isn't always forthcoming with providing the details on what can and cannot be deployed ... or what cannot exist in the deployment files themselves.  Fortunately, Apache Ant allows the ability to clean-up or delete files as part of the core process.  

Next, the files in the unDeployCode folder are configured.  

destructiveChanges.xml

Below, is a sample destructiveChanges.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>Account.AllAccounts</members>
        <members>Account.NewThisWeek</members>
        <name>ListView</name>
    </types>
    <types>
        <members>Account.Classification__c</members>
        <name>CustomField</name>
    </types>  
    <types>
        <members>ConversionPageController</members>    
        <members>testConversionPageController</members>       
        <members>ImportUtils</members> 
        <name>ApexClass</name>
    </types> 
    <types>
        <members>Conversion_Page</members>        
        <name>ApexPage</name>
    </types> 
    <types>
        <members>TriggerWeNoLongerNeed</members>   
        <name>ApexTrigger</name>
    </types> 
    <types>
        <members>Business Design Manager</members>        
        <name>Profile</name>
    </types>
    <types> 
        <members>CampaignMember-Campaign Member Page Layout</members>        
        <name>Layout</name>
    </types>
    <types>
        <members>unfiled$public/ContactFollowUpSAMPLE</members>
        <members>unfiled$public/LeadsNewassignmentnotificationSAMPLE</members>
        <members>unfiled$public/LeadsWebtoLeademailresponseSAMPLE</members>
        <members>unfiled$public/SUPPORTCaseResponsewithSolutionSAMPLE</members>
        <members>unfiled$public/SUPPORTCaseescalationnotificationSAMPLE</members>
        <members>unfiled$public/SUPPORTNewassignmentnotificationSAMPLE</members>
        <members>unfiled$public/SUPPORTWebtoCaseemailresponseSAMPLE</members>        
        <name>EmailTemplate</name>
    </types>       
    <version>34.0</version>
</Package>

In the destructiveChanges.xml file, the following items are being removed:

  • two list views from the Account section

  • a custom field from the Account object

  • two classes from our conversion project

  • one Apex Page from our conversion project

  • one trigger

  • one profile

  • one layout

  • several of the same Email templates

While it is possible to manually delete elements from your Orgs, you may not have the same ability in the Production instance.  Also, elements that are part of the Salesforce default design (like Email templates) may find their way back into your Orgs - which can cause problems if they find their way into Production.

package.xml

Finally, a sample package.xml is shown below:

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<version>34.0</version>
</Package>

Since this is basically an empty package.xml file, I haven't seen a need to change this file ... other than the version attribute.

After finishing the configuration of the files above, the files listed above need to be checked-in to Stash.  Once checked-in and merged, you should see your files in your branch.

Image title

Creating The Build Process

Atlassian Bamboo will handle the remainder of the steps for the Continuous Integration with Salesforce.  

Setting Up Global Variables

While not required, I recommend using Global Variables within Bamboo to avoid hard-coding references in the deployment process.   For each target Org, the following Global Variables should be created:

  • username (sfdc.sandbox_name.username)

  • password (sfdc.sandbox_name.password)

  • securitytoken (sfdc.sandbox_name.securitytoken)

  • serverurl (sfdc.sandbox_name.serverurl)

In the remainder of my examples, I will be using the dev01 Salesforce org.  As a result, my Global Variables will appear as shown below:

Image title

Creating the Project and Plan

Next, a new project called Salesforce was created in Bamboo.  Following our corporate standards, a new plan was created called develop under the Salesforce Project.  The plan has the following information:

Image title

Other Plan Items

Before we get to the Stages of the plan, we need to make sure the following items are set:

  • Repositories - should include the Stash repository which includes the Salesforce source code

  • Triggers - should be set to Stash Repository Triggered to automatically start the process

Creating The Stages

Next, we need to create the stages for the C/I process.  This is where the automation begins to take shape.  Below, is the configuration for the Run tests stage:

Image title

The Requirements tab should include Ant and a JDK (which we are using 1.8).

The Tasks are defined as shown below:

Image title

The Source Code Checkout is a standard task, which will pull the code from the target branch in Stash.  The Script task is simply echoing a "git status" to the logs.  The heart of this process is within the Ant task, which has the following attributes:

  • Description = Call deployEmptyCheckOnly (run tests only)

  • Executable = Ant

  • Build file = build.xml

  • Target = deployEmptyCheckOnly -Dsfdc.username=${bamboo.sfdc.dev01.username} -Dsfdc.password=${bamboo.sfdc.dev01.password}${bamboo.sfdc.dev01.securitytoken} -Dsfdc.serverurl=${bamboo.sfdc.dev01.serverurl}

  • Build JDK = Java 1.8

  • Working Subdirectory = build

The stage will fire the "depoloyEmptyCheckOnly" task in the build.xml file using Apache Ant.  Instead of relying on hard-coding values, the Global Variables will be substituted accordingly.

When called and finished properly the screen will display as shown below:

Image title

What's Next?

This article provided the instructions necessary with getting the Force Migration Tool files into a Stash repository.  A new project and plan were created in Bamboo, with a stage (called Run tests) automatically firing when changes are checked-in.

The next article will take things one-step further, by showing how a Release Candidate can be created.  This release candidate becomes a snapshot of the code base, which can be pushed to any configured Salesforce Org.  

Have a really great day!

Find out more about how Scalyr built a proprietary database that does not use text indexing for their log management tool, allowing customers to search 1TB of data in under a second. 

Topics:
salesforce ,bamboo ,integration ,salesforce integration

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}