Using Force.com with Subversion for Team Development

Introduction

A version control system can be an invaluable tool in enabling productive team development and release management. Force.com allows easy integration with such external tools (version control systems, IDE & scripting tools) to facilitate the development and deployment of applications in the cloud.

The power of Force.com lies in the fact that traditional development tools and processes can easily be incorporated into your process for developing Force.com applications, thus reducing the learning curve as well as leveraging industry best practices. In this short tutorial we will show you how you can start using Subversion, a free, open source version control system with Force.com to enable team development.

Scenario

Two developers, Harry and Sally, need to collaborate to develop the business and testing logic for the Mileage example from the Force.com Workbook. Though we recommend that you take a quick look at the example and the code, understanding the code is not required to follow along. This tutorial shows how Harry and Sally can interface and develop as a team by using a code repository.

The structure of the tutorial is as follows:

  • Setting up Subversion - this section shows you how to set up a simple Subversion repository.
  • Setting up the Developer Environment - you develop in the cloud, and store a local representation of your application in your Subversion repository. This section shows how the team should set up their individual developer environments.
  • Team Development - this section contains the meat of the tutorial. It shows how Harry and Sally can each make changes in the development environments, and use the subversion repository to communicate these changes.
  • Promoting the Code - this section sketches the next step; how to take the collaboratively developed code and push it to a production or testing environment.

Finally, the tutorial provides a little background information on metadata, and a number of resources to get you going.

Setting up a Subversion Server

We're going to be using Subversion as our source code repository. Subversion has both a server and clients. In this section we'll look at setting up the server. You would typically use a single Subversion server. In our case, Harry and Sally will be connecting to this single shared repository using their own Subversion clients.

As an alternative to managing your own SVN server there are a number of preconfigured online subversion services like ProjectLocker which allow you to keep your source code management in the cloud.

Install Subversion

  • Download Subversion. We downloaded it from this site and chose Windows binaries in the Get Subversion section.
  • Unzip to a folder of choice. We used C:\software\subversion.
  • Go to Control Panel ->System-Advanced Tab and choose Environment Variables button on the bottom. Add the binaries path to the path environment variable for the machine. We added C:\software\subversion\bin.
  • Create and set the value of a new environment variable called SVN_EDITOR to an editor of your choice - for example c:\windows\notepad.

If you're using OS X, subversion is already installed.

Create a repository and add authorized users

The repository stores the files that are under the control of the version control system.

> svnadmin create c:\software\svn-test\repos

Go to c:\software\svn-test\repos\conf and uncomment the following lines in svnserve.conf in the [general] section of the file.

[general]
anon-access = read
auth-access = write
password-db = passwd

In the same folder, open the file called passwd and uncomment the two lines as shown below

[users]
harry = harryssecret
sally = sallyssecret


Start up the Subversion server

Open a command prompt window and type in the command below to

> svnserve --daemon --root "c:\software\svn-test\repos"


Create a new project

Open a second command prompt window and type the following

> svn mkdir -m "Directory created for Mileage project" svn://localhost/mileage

The default admin password is blank so just hit return. For a given project, it is a common practice to create child directories to hold the main line of development, branch copies and the tag directories. By convention these are called trunk, branches and tags respectively. Let's go ahead and create them as shown below. We will only be working on the main line in this example.

> svn mkdir -m "Trunk" svn://localhost/mileage/trunk
> svn mkdir -m "Branches" svn://localhost/mileage/branches
> svn mkdir -m "Tags" svn://localhost/mileage/tags

// After the successful execution of each of these command 
// you should see a message  "Committed revision n".

// You can list all the directories created with the list command
> svn list svn://localhost/mileage 

branches/
tags/
trunk/

Now that you have set up a Subversion server, let's look at the development environments for Harry and Sally.

Setting up the Developer Environment

Both Harry and Sally should have their own org to build and test against. Either a Developer Edition or Developer Sandbox can be used for this purpose - see An Introduction to Environments to learn more about environments. We use Developer Edition (DE) orgs in this tutorial.

Each developer machine should also have a copy of the Force.com Migration tool. The Force.com Migration Guide referenced on this page has detailed installation instructions. Sample files required for the scenario is attached Migration-tool-files.zip. There are three files in this download - build.properties that has the connection information (username and password), build.xml which has custom Ant tasks and package.xml that lists the components that will be retrieved and deployed. The build.properties file should be updated for each developers environment - in particular you'll need to set up the authentication details for the orgs. So Harry and Sally would change it to point to their own DE orgs. Finally, you would need the Subversion client on each of the developer machines.

The logical structure is depicted in the following figure.

Svn-logicalv2.png

For the rest of this tutorial we're going to use a svn application from the command line. We got this application by installing a Subversion client. In fact, if you install the Subversion server, you get the client installed as well. Typically however, you will run the clients on each developer's machine, and the server on another. See the Additional Resources section below for more pointers to Subversion clients.

Team Development

With Subversion installed and the developer's individual environments, we are ready to begin developing code. We will assume that Harry and Sally use their own favorite Force.com tool or even just a text editor to actually write the code. We will focus on getting the code into Subversion and deploying it in their org. Here's a typical team interaction:

  • Harry creates the Mileage database object using the online builder environment after logging into his DE org. He also creates a trigger (MileateTrigger), and the skeletons of a utility class (MileageUtil) and testing class (MileageTrackerTestSuite). After creating the object and classes in the org, he retrieves them into a local temporary directory using the Force.com migration tool and its retrieveCode task. The retrieved content and the deployed code is driven by the package.xml file - we are only retrieving/deploying the custom object definition, the Apex code and the trigger definition.


> ant retrieveCode 


In terms of the metadata files, the above object and classes will be found in the files Mileage__c.object, MileageUtil.cls, MileageTrackerTestSuite.cls, and MileageTrigger.trigger - available in the data retrieved using the Ant task.

  • Harry's machine now has a local copy of the code (and the associated metadata files) from his DE org. Now he needs to populate the Subversion repository with this code by executing a one-time import into the repository. (When you run the command below, you should see a message called Adding with the file name for each of the files followed by a Committed revision n message.)


> svn import temp svn://localhost/mileage/trunk -m "Initial import"


The initial set of files that was retrieved into the temp directory by the Ant command can now be deleted - they're now all in the repository.

  • Though Harry imported these files into the repository, he now needs a local copy again, this time under Subversion control. Harry needs to check out the files into a working directory. He checks out the files using the command below. A directory called trunk is created and within it another directory called .svn is created. Changes that Harry makes to his local copy of the file will now be tracked within the .svn directory by Subversion.


> svn checkout svn://localhost/mileage/trunk 
// You will see a message similar to below
A    trunk\triggers
A    trunk\triggers\MileageTrigger.trigger
A    trunk\triggers\MileageTrigger.trigger-meta.xml
A    trunk\objects
A    trunk\objects\Mileage__c.object
A    trunk\package.xml
A    trunk\classes
A    trunk\classes\MileageUtil.cls
A    trunk\classes\MileageUtil.cls-meta.xml
A    trunk\classes\MileageTrackerTestSuite.cls
A    trunk\classes\MileageTrackerTestSuite.cls-meta.xml
Checked out revision 5.


  • Sally checks out the contents of the project from Subversion into her working directory. Subversion creates a trunk directory and the .svn directory to keep track of changes that Sally makes on her machine.


> svn checkout svn://localhost/mileage/trunk
// Message similar to above should appear 


Now Sally has a local copy of the source code under Subversion control, just like Harry.

  • Remember that Apex code can only execute on Force.com servers, so having it on the local drive doesn't do much good. Sally deploys these into her DE org - she now has a environment close to Harry's. She uses the Ant task deployCode (see sample in attached build.xml file) to push the code from her local machine into her org.


> ant deployCode 

Now Harry and Sally have the same code running in their own individual DE orgs. They also have local copies of that code retrieved from the shared Subversion server.

  • Harry now makes changes. He is done coding the business logic. He deploys into his DE org and tests it there to make sure there are no errors. Once he is satisfied, he checks it into Subversion.


// find difference between local copy and the one in the repository
svn diff MileageUtil.cls

// Harry is satisfied so he updates the repository. 
// The update will tell us if there are any conflicts
> svn update MileageUtil.cls 

// There are none in this case so he can commit it.  The changes
// are now visible in the repository.
> svn commit -m "Coded the business logic" MileageUtil.cls 


  • Sally starts coding the test suite. She checks out the latest version of Harry's code, deploys it into her DE org, and runs her test suite against it.
  • While testing Sally notices that Harry has set the value of the constant MAX_MILES_PER_DAY to 300 in MileageUtil.cls. Her understanding of the requirement is that the correct value should be 500. She talks to Harry and the business analyst / customer who clarifies that the correct value should indeed be 500. Sally makes the change to her local copy of MileageUtil and checks it into Subversion.


> svn update MileageUtil.cls
// Conflict detected - choose (e)
Conflict discovered in 'MileageUtil.cls'.
Select: (p) postpone, (df) diff-full, (e) edit,
        (mc) mine-conflict, (tc) theirs-conflict,
        (s) show all options: e
// The file is opened in an editor.  Delete the version you don't need and save the file
// Then select (r) to resolve the conflict
Select: (p) postpone, (df) diff-full, (e) edit, (r) resolved,
        (mc) mine-conflict, (tc) theirs-conflict,
        (s) show all options: r
G    MileageUtil.cls
Updated to revision 7.

// Now commit the change
> svn commit -m "Changed daily mileage limit - 300 to 500 miles per day" MileageUtil.cls


  • After she is satisfied with her unit testing code (MileageTrackerTestSuite.cls) in her DE she checks it in


> svn update MileageTrackerTestSuite.cls
> svn commit -m "Unit tests for MileageUtil" MileageTrackerTestSuite.cls 


Note the merge process - Subversion uses a versioning model call Copy-Modify-Merge that allows developers to simultaneously work on the same file by requiring the developers to manually merge any changes which can't be figured out by syntactical merging. A common practice is to branch of a main line of development (trunks and branches) and merge changes on a periodic basis.

The version control system thus becomes the single source of truth since all code sharing between the developers take place only through check in and checkout from the repository. Notice how much superior it is to ad-hoc sharing - now we can track who made what change when and even revert back to an older version if needed. If you have used version control system before the work cycle implied above should be very familiar. This highlights a benefit of Force.com we mentioned earlier, easy integration into your existing development practices. The only difference is that instead of compiling and executing the code on our local machine we deploy it to an org where these activities can take place. The Force.com Migration tool bridges the environment on the developer machine to their org environment.

Promoting the Code

After the development is done, the code can then be pushed to something like a full copy Sandbox environment (see An Introduction to Environments) for further testing (integration testing, user acceptance testing and so on). The process is similar - check out the code from Subversion and deploy into Sandbox. See the figure below. The promotion from full copy Sandbox to production is similar. Since the version control system is our definitive and single source of truth for all our code, we can be confident that we are promoting the correct code.

Svn-promotev2.png

Here, we have a staging machine. Logically, you'd typically have this to serve as the conduit to the production or testing environment. In reality, it could simply be Harry or Sally's machine - whoever has the rights to push stuff to production.

The Migration Tool, Metadata API and Subversion

The Force.com Migration Tool provided the bridge between the code in an org running in the cloud, and the developer machine with the Subversion repository. The files deployed to, or retrieved from, an org are driven by the package.xml file, as we saw in our sample above. (See the references below on the metadata API to learn more about this file). Notice that, in addition to each source code file, the retrieve task also retrieves another XML file e.g. MileageUtil.cls-meta.xml. This XML document is the metadata associated with the class file MileageUtil.cls. All components on Force.com have associated metadata and for some components there is no 'code' - it is all metadata.

The Force.com Metadata API is in fact a SOAP-based web sevices - and it provides commands to retrieve and deploy metadata. The migration tool we have been using is a simple client built on top of that API. Retrieve and deploy are atomic operations, and the content of each call is driven by the associated package.xml manifest file.

Though the Force.com IDE provides a rich environment for editing Apex code and Visualforce pages, it can be awkward to directly edit other XML metadata files. In this case Force.com (see An Introduction to Point-and-Click App Building with Force.com) with its GUI tools provides the best environment to build and change things, while the Metadata API/migration tool provides the mechanism to move changes from one org to another or to a version control system.

At this time some amount of manual configuration is still needed in the target org, because the Metadata API does not expose every bit of customization done in an org. Furthermore, there is a limit of 1500 components that can be retrieved or deployed in a single operation. If you have a larger number of components you will have to split it into batches.

Subversion (and almost all version control systems) is agnostic to what it stores - code, documents and even binary data can be stored and versioned. We highly recommend that you take advantage of this feature to store everything related to your project (components, migration tool files, client code, documentation etc.) into Subversion using scripting tools to make the process automated whenever possible.

Summary

Using a version control system as part of your development effort improves team productivity and makes your release management smoother and more predictable. This tutorial looks at using Subversion, a free, open source solution; but integration with other version control systems like CVS, VSS, etc. would work in a similar manner. These tools provide many more features than those covered in this article to help with development and release management, and should be part of every development project.

References

Additional Resources

GUI-based Subversion Clients

We used the command line tools to demonstrate the concepts and to show you how you can incorporate the migration tool and Subversion into your own scripts. There are many GUI tools available - Subclipse, a plug-in to Eclipse IDE and Tortoise SVN a Windows client are all worth checking out. This blog post shows how to use Subclipse with Force.com IDE.

Cloud-based Version Control Repository

Subversion is free and open source so you can install it at no cost, but that still leaves you with the hassle of configuring, maintaining, and backing up the software. Another popular option is to leverage a cloud-based version control provider.

Open source hosting sites like Google Code offer free version control repositories for open source projects, and are a good choice if you are not concerned about others viewing and using your code. See Developer Force's Code Share for many projects that use this kind of version control.

For commercial projects, there are many choices of paid providers. CollabNet maintains the Subversion open source project and has a large base of enterprise customers, but a quick search will turn up a large number of other options.

About the Author

Nick Simha is a Partner Enablement Manager and Platform Evangelist working with Salesforce.com's consulting partners to help them build innovative cloud applications for our customers. He would like to thank Jon Plax, Jon Mountjoy and Jesse Lorenz for their insightful feedback on this article.