9

I have the following set up in my build.xml file:

<target name="retrievePackage" description="Retrieves the specified package from the specified organization. Pass the name of the deployment file to build the package from via -DdeployFile=[xml file name]." >
    <delete dir="${basedir}/deploystage" />
    <mkdir dir="${basedir}/deploystage" />

    <echo>Retrieving code into ${basedir}/deploystage from ${sf.username}, ${sf.server} from packages/${deployFile}</echo>
    <sf:retrieve 
       username="${sf.username}" 
       password="${sf.password}" 
       serverurl="${sf.server}" 
       retrieveTarget="${basedir}/deploystage"
       unpackaged="packages/${deployFile}"
       pollWaitMillis="10000"
       maxPoll="100"/>
</target>

<target name="deployPackage" description="Deploys everything stored in the /deploystage directory. You must specify the org to deploy to via -propertyfile=[org property file name]. Use -DrunAllTests=[booleanValue] to run all the tests or skip them. Use -DisValidate=[booleanValue] to determine if you only want to validate the deploy (i.e., not actually deploy anything)">
    <delete file="${basedir}/deploystage/deploy.zip"/>
    <zip destfile="${basedir}/deploystage/deploy.zip" update="true">
        <fileset dir="${basedir}/deploystage" includes="**/*"/>
    </zip>
    <sf:deploy username="${sf.username}" password="${sf.password}" serverurl="${sf.server}" zipFile="${basedir}/deploystage/deploy.zip" maxPoll="2000" pollWaitMillis="10000" rollbackOnError="true" runAllTests="${runAllTests}" checkOnly="${isValidate}" logType="Debugonly" singlePackage="true" allowMissingFiles="false" />
</target>

My property file looks like:

# Specify the login credentials for the desired Salesforce organization
sf.username=trifecta@trifecta.com.test
sf.password=not-a-real-password

# Use 'https://login.salesforce.com' for production or developer edition (the default if not specified).
# Use 'https://test.salesforce.com for sandbox.
sf.server=https://test.salesforce.com

and my package file looks like:

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>Site_Com_Access</members>
        <name>PermissionSet</name>
    </types>
    <types>
        <members>Custom: Sales</members>
        <name>Profile</name>
    </types>
    <version>27.0</version>
</Package>

Essentially, the way this works is you can call a statement like:

ant retrievePackage -DdeployFile=package-test.xml -propertyfile test.properties

which will return the selected metadata with an output that looks like:

Buildfile: /Users/jessealtman/Desktop/deploy/build.xml

retrievePackage:
   [delete] Deleting directory /Users/jessealtman/Desktop/deploy/deploystage
    [mkdir] Created dir: /Users/jessealtman/Desktop/deploy/deploystage
     [echo] Retrieving code into /Users/jessealtman/Desktop/deploy/deploystage from trifecta@trifecta.com.test, https://test.salesforce.com from packages/package-test.xml
[sf:retrieve] Request for a retrieve submitted successfully.
[sf:retrieve] Request Id for the current retrieve task: 04sZ00000011VfRIAU
[sf:retrieve] Waiting for server to finish processing the request...
[sf:retrieve] Request Status: Completed
[sf:retrieve] Finished request 04sZ00000011VfRIAU successfully.

BUILD SUCCESSFUL
Total time: 12 seconds

Awesome, looks like everything went really well. Let's try our deploy statement (just validating):

ant deployPackage -DisValidate=true -DrunAllTests=false -propertyfile test2.properties

This returns with the following result:

Buildfile: /Users/jessealtman/Desktop/deploy/build.xml

deployPackage:
      [zip] Building zip: /Users/jessealtman/Desktop/deploy/deploystage/deploy.zip
[sf:deploy] Request for a deploy submitted successfully.
[sf:deploy] Request Id for the current deploy task: 04sJ0000000oFvxIAE
[sf:deploy] Waiting for server to finish processing the request...
[sf:deploy] Request Status: Completed

BUILD FAILED
/Users/jessealtman/Desktop/deploy/build.xml:317: FAILURES:
Error: package.xml(Site_Com_Access):An object 'Site_Com_Access' of type PermissionSet was named in package.xml, but was not found in zipped directory
Error: package.xml(Custom: Sales):An object 'Custom: Sales' of type Profile was named in package.xml, but was not found in zipped directory

What happened here? We retrieved perfectly fine, what went wrong?

16

Well let's take a look at your deploystage directory

deploystage directory

So, this is really interesting. There are two things that pop out right away.

Firstly, it looks like our package.xml file wasn't set up correctly to begin with. The following section:

<types>
    <members>Site_Com_Access</members>
    <name>PermissionSet</name>
</types> 

returned a permission set named Site_com_Access.permissionset. Notice how the C in com is actually lower case. That is how it was set up in the original environment. sf:retrieve allows you more leeway than sf:deploy when it comes to capitalization. In sf:deploy, the package.xml file must match exactly what is in your file system. This brings us to our next point:

There are certain characters, such as a colon (:), that simply can't be part of a name of a file. The following section from the package.xml file:

<types>
    <members>Custom: Sales</members>
    <name>Profile</name>
</types>

actually returned a file named Custom%3A Sales.profile. The colon (:) got encoded to %3A when the file was saved.


So, how do we fix this? Well, you can rename your profile to not use any reserved characters. However, if you absolutely must have that colon, you need to keep the package-test.xml file you originally used the same in regards to the profile, but change the package.xml file in deploystage to:

<types>
    <members>Custom%3A Sales</members>
    <name>Profile</name>
</types>

The profile will be encoded character will be reverted by Salesforce during deploy and your profile will properly deploy as Custom: Sales. Also, we need to fix our original package.xml file to point correctly to the true API name of our permission set. This change will then be duplicated to our package.xml file in deploystage upon retrieve:

<types>
    <members>Site_com_Access</members>
    <name>PermissionSet</name>
</types>

So, with our new changes, what does our original validate deploy statement return?

ant deployPackage -DisValidate=true -DrunAllTests=false -propertyfile test2.properties

returns

Buildfile: /Users/jessealtman/Desktop/deploy/build.xml

deployPackage:
   [delete] Deleting: /Users/jessealtman/Desktop/deploy/deploystage/deploy.zip
      [zip] Building zip: /Users/jessealtman/Desktop/deploy/deploystage/deploy.zip
[sf:deploy] Request for a deploy submitted successfully.
[sf:deploy] Request Id for the current deploy task: 04sJ0000000oFt0IAE
[sf:deploy] Waiting for server to finish processing the request...
[sf:deploy] Request Status: InProgress
[sf:deploy] Request Status: Completed
[sf:deploy] Finished request 04sJ0000000oFt0IAE successfully.

BUILD SUCCESSFUL
Total time: 22 seconds

So, what does this tell us?

  • sf:retrieve is more lenient that sf:deploy, however we need to be cognizant of this if we eventually plan on deploying from the same package.xml file
  • Encoded characters have to be properly referenced in a package.xml file during a deploy. Salesforce will return those characters to the original, correct state upon deploy

Some tips to avoid running into a situation like this:

  • Avoid any restricted characters if at all possible. There is usually very little need to do this and it just causes problems down the road.
  • Be consistent in your API names. It is hard to remember exactly which letter was capitalized if you are inconsistent. I would suggest keeping every character after an underscore (_) capitalized. It is beneficial at times when creating a new field/object to actually change the API name and not just go with the suggested name. If you absolutely have no control over API names, it is a good practice to build your package.xml file using the Workbench. It will help you find names correctly on your first try.
| improve this answer | |
  • 1
    thanks for sharing, that was a great walk through of ant debugging – Ralph Callaway Feb 28 '13 at 16:09
  • Awesome! And great to know what to do to avoid running into these types of issues! – Peter Knolle Feb 28 '13 at 20:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.