This post assumes we have made the build.xml file described in that posting.
Using the Ant Force.com Migration Tool:
- I'll show you how to perform a typical retrieve from Production; deploy to Sandbox; fix; deploy to Sandbox and test; then deploy to Producton.
- Then I'll show you how to create a new APEX Class.
- Then I'll show you how to create a new APEX Trigger.
Typical workflow to fix something on Production.
- Edit the workArea/package.xml file to specify what classes, triggers or object I need to fix. See this post for more how to do this.
- Run the ant tool to retrieve from production.
- ant -v -lib . -f build.xml -Dtarget=prod retrieve
- Run the ant tool to deploy to the sandbox.
- ant -v -lib . -f build.xml -Dtarget=test deploy
- Assuming the deploy worked it is now time to fix what you need to fix. Include test cases verify your fix and provide the 75+% test coverage required by Salesforce. Strive for 90% coverage.
- Run the ant tool to deploy to the sandbox. Test cases will run to validate your fix.
- ant -v -lib . -f build.xml -Dtarget=test deploy
- Run the ant tool to deploy to production.
- ant -v -lib . -f build.xml -Dtarget=prod deploy
Here is the complete build file:
<project name="Salesforce Project" default="work" basedir="." xmlns:sf="antlib:com.salesforce">
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
<target name="setup" >
<!-- on command line include "-DtargetDir=src" to change the target -->
<property name="targetDir" value="workarea" />
<if>
<equals arg1="${target}" arg2="test" />
<then>
<property file="buildTest.properties"/>
<property name="system" value="TEST" />
</then>
<elseif>
<equals arg1="${target}" arg2="prod" />
<then>
<property file="buildProd.properties"/>
<property name="system" value="PROD" />
</then>
</elseif>
<else>
<echo message="The value of property target is not 'test' or 'prod'" level="error" />
<fail/>
</else>
</if>
</target>
<target name="work" depends="setup">
<echo>The ${system} user name is ${sf.username}</echo>
</target>
<!-- Retrieve an unpackaged set of metadata from your org -->
<!-- The file ${targetDir}/package.xml lists what is to be retrieved -->
<target name="retrieve" depends="setup">
<!-- Retrieve the contents into another directory -->
<sf:retrieve username="${sf.username}" password="${sf.password}" serverurl="${sf.serverurl}" retrieveTarget="${targetDir}" unpackaged="${targetDir}/package.xml"/>
</target>
<!-- Deploy the unpackaged set of metadata retrieved with retrieveUnpackaged -->
<!-- The file ${targetDir}/package.xml lists what is to be depployed -->
<target name="deploy" depends="setup">
<sf:deploy username="${sf.username}" password="${sf.password}" serverurl="${sf.serverurl}" deployRoot="${targetDir}"/>
</target>
</project>
Create APEX Class Using Ant
So here is a snippet to include in your build.xml file to generate a blank APEX class.<!--
Sample: Create an after upsert trigger on object Opportunity
ant -v -lib . -f build.xml -Dtarget=test -DclassName=Foo -Dtype=after createClass
Results:
Two files:
Foo.cls
Foo.cls-meta.xml
-->
<target name="createClass" depends="setup" >
<fail unless="className" message="Must provide className (-DclassName=Foo) "/>
<mkdir dir="${targetDir}/classes"/>
<echo file="${targetDir}/classes/${className}.cls" append="false">public with sharing class ${className} {
}</echo>
<copy file="templates/classes.meta.xml" tofile="${targetDir}/triggers/${className}.cls-meta.xml" />
</target>
Before running this create a directory for the templates
~/Documents/salesforce/dev$ mkdir templates/
Then create the file classes.meta.xml and insert the following:
<?xml version="1.0" encoding="UTF-8"?>
<ApexClasses xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>26.0</apiVersion>
<status>Active</status>
</ApexClasses>
Now when you run ant like this
ant -v -lib . -f build.xml -Dtarget=test -Dobject=Opportunity -Dtype=after createTrigger
you get triggers/OpportunityAfterUpsertTrigger.trigger with this content
trigger OpportunityAfterUpsertTrigger on Opportunity (after insert, after update) {
}
and you get triggers/OpportunityAfterUpsertTrigger.trigger-meta.xml with the necessary meta definition. When you deploy this new class will be pushed to the server.
Create APEX Trigger Using Ant
I have a simple naming convention for my trigger files. Object + Before or After + "UpsertTrigger". For example OpportunityAfterUpsertTrigger works on Opportunity objects after insert or update. I generally only build before or after upsert triggers; meaning I generally have triggers like thistrigger OpportunityAfterUpsertTrigger on Opportunity (after insert, after update) {
}
or this
trigger OpportunityBeforeUpsertTrigger on Opportunity (before insert, before update) {
}
Inside these triggers I generally collect the objects that need to be worked on and ship them over to another class to do the work and testing.
So here is a snippet to include in your build.xml file to generate a blank trigger.
<!--
Sample: Create an after upsert trigger on object Opportunity
ant -v -lib . -f build.xml -Dtarget=test -Dobject=Opportunity -Dtype=after createTrigger
Results:
Two files:
OpportunityAfterUpsertTrigger.trigger
OpportunityAfterUpsertTrigger.trigger-meta.xml
-->
<target name="createTrigger" depends="setup" >
<fail unless="object" message="Must provide Object for the trigger"/>
<fail unless="type" message="Must provide type 'before' or 'after' "/>
<if>
<equals arg1="${type}" arg2="before" />
<then>
<property name="triggerName" value="${object}BeforeUpsertTrigger" />
</then>
<elseif>
<equals arg1="${type}" arg2="after" />
<then>
<property name="triggerName" value="${object}AfterUpsertTrigger" />
</then>
</elseif>
<else>
<echo message="The value of property type is not 'before' or 'after'" level="error" />
<fail/>
</else>
</if>
<mkdir dir="${targetDir}/triggers"/>
<echo file="${targetDir}/triggers/${triggerName}.trigger" append="false">trigger ${triggerName} on ${object}</echo>
<if> <equals arg1="${type}" arg2="before" />
<then>
<echo file="${targetDir}/triggers/${triggerName}.trigger" append="true"> (before insert, before update) {
}</echo>
</then>
<elseif> <equals arg1="${type}" arg2="after" />
<then>
<echo file="${targetDir}/triggers/${triggerName}.trigger" append="true"> (after insert, after update) {
}</echo>
</then>
</elseif>
</if>
<copy file="templates/trigger.meta.xml" tofile="${targetDir}/triggers/${triggerName}.trigger-meta.xml" />
</target>
Before running this create a directory for the templates
~/Documents/salesforce/dev$ mkdir templates/
Then create the file trigger.meta.xml and insert the following:
<?xml version="1.0" encoding="UTF-8"?>
<ApexTrigger xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>26.0</apiVersion>
<status>Active</status>
</ApexTrigger>
Now when you run ant like this
ant -v -lib . -f build.xml -Dtarget=test -Dobject=Opportunity -Dtype=after createTrigger
you get triggers/OpportunityAfterUpsertTrigger.trigger with this content
trigger OpportunityAfterUpsertTrigger on Opportunity (after insert, after update) {
}
and you get triggers/OpportunityAfterUpsertTrigger.trigger-meta.xml with the necessary meta definition. When you deploy this new class will be pushed to the server.
Have you tried this module for testing: https://github.com/DeveloperForceJapan/ApexTestPlus/blob/master/README.md
ReplyDeleteis there any way or the slightest possibility for us to hack to to see the managed package code in salesforce apps ?
ReplyDelete