Using Rational Team Concert on Mac with Xcode (Part 1)
Overview
In order to build Mac applications you use Apple’s Xcode IDE. It has a rich set of tools for developing, debugging, testing and building your application. Rational Team Concert (RTC) can manage the revisions of your code, help you to work collaboratively with your team, track work to be done, manage your builds and releases. The two applications can complement each other and make it easier to manage your project.
Many people who use RTC do so through its Eclipse client. However, at the time of writing there is no support for writing Mac applications using Eclipse or any of its extension. RTC provides a web interface and a command-line interface with a combined set of capabilities that cover much of what is possible with the Eclipse client. The reader should be comfortable to proficient with command-line interfaces in order to work in this way.
This article is part of a three-part series. The first part will show you how to take your Xcode project and share it to an RTC server. Once the code is shared you can begin organizing your changes into change sets so that you can inspect the history of your project to see the related changes. Also, this project will be backed up on the server in case your hard drive malfunctions or an accidental deletion occurs.
The second part of the series will cover how to work with Xcode and RTC in a team environment where multiple people are working on the same Xcode project. Finally, the third installment shows you how to automate your builds and tests.
Setting up your environment
The Xcode IDE includes much of what you need to develop Mac applications. We are going to be using the built-in Mac OS X Terminal app to first install and later use the Jazz SCM CLI on a regular basis. You should probably keep the Terminal app in an easily accessible place such as on the Dock. The easiest way to run the Terminal is to invoke the Spotlight tool (magnifying glass icon) on the top-right of your screen, type in the text "terminal" (without the quotes) and click on the entry under "Applications." Once the Terminal app is running you can right-click (or Control-click) on it in the Dock and choose Options > Keep in Dock. The terminal is easily run in the future by just clicking on it in the Dock.
There is an RTC client download available from jazz.net website that includes both the Eclipse IDE client and the CLI. Although, you won’t need Eclipse client in this article there are certain occasions where you will need it. The zip can be found on the jazz.net website in Downloads > Rational Team Concert > All Downloads > Plain Zips > Client for Eclipse IDE
Once you download the zip you can extract it into some well-known place (e.g. /Users/Chris/jazz) and add it to your path by modifying your bash profile (e.g. /Users/Chris/.bash_profile). The extra path entry adds some of Xcode’s own command line tools to your path.
export PATH=$PATH:/Users/Chris/jazz/scmtools/eclipse:/Developer/usr/bin
The CLI experience can be customized fairly easily through the use of shell scripts. You can download and extract this zip into your jazz/scmtools/eclipse directory to get some special tools for doing graphical merges and differences using Apple’s own difference viewer application. The following sections are written with the assumption that these special tools are present in your install.
Xcode uses files that Jazz SCM is not familiar with in formats that are not auto-detectable. If it does not yet exist create a text file in /Users/Chris/.jazz-scm/magic.properties. Add the following information to that file:
*.m: mime: text/plain; delim: platform *.xib: mime: text/xml; delim: platform *.pch: mime: text/plain; delim: platform *.plist: mime: text/xml; delim: platform *.strings: mime: text/xml; delim: platform *.pbxproj: mime: text/plain; delim: platform *.sh: mime: text/plain; delim: platform
Now you should be able to start up the CLI and run the following commands from the Terminal:
$ lscm help $ lscm login -r https://myserver:9443/jazz -u Chris -c -n myserver
The first command should bring up the help screen for the CLI. The second should prompt you for a password to log into your server. The "-c" option caches the password so you don’t have to type it again every time you run lscm. With the "-n" option you don’t have to type in the full server URL in the future and you can use the nick name "myserver" instead.
Sharing your code with the server
When you create an Xcode project and save it Xcode will usually choose your Documents directory for your project. In Jazz SCM you put the files and directories you want to share in a sandbox. Since the Documents directory will contain items that you do not want to share it is probably not a suitable sandbox. Instead, create an empty sandbox directory where you will keep all of your shared items (e.g. /Users/Chris/sandbox).
$ mkdir /Users/Chris/sandbox
Once you have a suitable sandbox you can either copy over an existing Xcode project directory or create a new Xcode project in your sandbox. If you are copying over an existing project don’t forget to start making your changes in the sandbox and not in the original directory (ie. the one in the Documents directory).
Xcode creates certain types of files that should not be shared into your SCM system (e.g. build artifacts and user-specific settings). Jazz SCM needs to know about these file types so that it doesn’t share them on the server or show them as outgoing changes. Create a special ".jazzignore" file inside your Xcode project directory (in the sandbox) with this information.
core.ignore= build core.ignore.recursive= {.DS_STORE} {.DS_Store} {xcuserdata} {*.swp} {*~.nib} {*.pbxuser} {*.mode1v3} {*.mode2v3}
A repository workspace is a place that is reserved on the Jazz SCM server for you to share your items. It retains a history of the changes to your items and allows you to put your projects into different components. We will create one repository workspace with one component for this Xcode project.
$ lscm create workspace -e -r myserver MyMacWorkspace $ lscm create component -r myserver CoolXcodeProject MyMacWorkspace
The above commands will create the repository workspace and create an empty component that lives in this repository workspace for your Xcode project. You can share your project with the following command.
$ cd /Users/Chris/sandbox $ lscm share -r myserver MyMacWorkspace CoolXcodeProject MyXcodeProjectDirectoryName
Once your project is shared with the Jazz SCM server there is a backup copy of your work. You can begin sharing your changes using change sets. The next section will cover a number of powerful capabilities that become availble once you have shared your code.
Working with Jazz SCM
There are a number of Jazz SCM CLI commands and some custom scripts to help manage the changes to your code. For now, we will focus on how to work alone with your project. The second part of this series of articles will cover in more detail how you can work with Jazz SCM in a team.
Keep your changes organized into change sets
When you shared your Xcode project Jazz SCM created one very large change set with all of the files and directories. Change sets group together a set of changes as part of a single activity, in this case an initial share. You can find the active change sets by running the status command.
$ lscm status Workspace: (1135) "MyMacWorkspace" <-> (1135) "MyMacWorkspace" Component: (1136) "CoolXcodeProject" Baseline: (1137) 1 "Initial Baseline" Outgoing: Change sets: (1138) *--@ "Share" 04-Jun-2012 02:22 PM
You can see from the status that there is a single change set called "Share." It includes changes for every file in your Xcode project that isn’t ignored. This change set is probably not very interesting so you can hide it by completing; it. The complete command needs the alias for the change set, which is shown in round brackets beside the change set date and label: 1138.
$ lscm changeset complete 1138 Change set completed. $ lscm status Workspace: (1135) "MyMacWorkspace" <-> (1135) "MyMacWorkspace" Component: (1136) "CoolXcodeProject" Baseline: (1137) 1 "Initial Baseline"
Once a change set is complete it is no longer shown in your status, although it can be found by exploring the history. No new changes can be added to the change set once it is complete.
A change set can be created in two different ways. You can simply begin changing your files/directories in the sandbox and check the changes in when you are done. Jazz SCM automatically checks the changes into an existing incomplete change set or it creates a new change set. Otherwise, you can create a change set ahead of time and check in your changes into it.
$ lscm create changeset "Fix the unit tests" Created change set (1139). $ lscm status Workspace: (1135) "MyMacWorkspace" <-> (1135) "MyMacWorkspace" Component: (1136) "CoolXcodeProject" Baseline: (1137) 1 "Initial Baseline" Outgoing: Change sets: (1139) *--@ "Fix the unit tests" 04-Jun-2012 02:39 PM
When you change items in your sandbox you check the changes in by running the checkin command with the file that you changed. You can provide the change set alias or let Jazz SCM choose the change set for you.
$ lscm checkin -c 1139 MyXcodeProjectTests.m Workspace: (1135) "MyMacWorkspace" <-> (1135) "MyMacWorkspace" Component: (1136) "CoolXcodeProject" Baseline: (1137) 1 "Initial Baseline" Outgoing: Change sets: (1139) *--@ "Fix the unit tests" 04-Jun-2012 02:45 PM Changes: ---c- /MyXcodeProject/MyXcodeProjectTests/MyXcodeProjectTests.m
Sometimes when working with your code you may find that you don’t remember the full impact of all of your changes. Jazz SCM will scan your sandbox looking for changes when you run the status command. It reports any local changes as "Unresolved."
$ lscm status Workspace: (1135) "MyMacWorkspace" <-> (1135) "MyMacWorkspace" Component: (1136) "CoolXcodeProject" Baseline: (1137) 1 "Initial Baseline" Unresolved: -c- /MyXcodeProject/MyXcodeProjectTests/MyXcodeProjectTests.m
You can undo local changes using the undo command. This is useful in the case of accidental or simple whitespace changes. Local changes can be checked in one at a time as shown in the previous example. To check in a group of local changes use the path to the highest directory that contains all of the changes.
$ lscm undo MyXcodeProjectTests.m Changes successfully undone. ... OR ... $ lscm checkin . Workspace: (1135) "MyMacWorkspace" <-> (1135) "MyMacWorkspace" Component: (1136) "CoolXcodeProject" Baseline: (1137) 1 "Initial Baseline" Outgoing: Change sets: (1141) *--@ "<No comment>" 04-Jun-2012 02:55 PM Changes: ---c- /MyXcodeProject/MyXcodeProjectTests/MyXcodeProjectTests.m
It is always good to check in local changes sooner rather than later so that they are backed up. If you checked in a change that you don’t want you can undo that change from the change set as long as it is not marked as complete. The undo command will undo any local changes for the file like in the above example. Otherwise, it tries to undo it from a change set. If you don’t want an entire change set you can discard it completely.
$ lscm undo MyXcodeProjectTests.m Changes successfully undone. ... OR ... $ lscm discard 1141 Change sets successfully discarded.
When items are deleted there is a special way to check in the delete. You invoke the checkin command in the normal way but you provide the path to the parent directory of the deleted item instead of the path to the item itself. Use caution because this will also check in any other changes to items in that directory.
Load to recover from a disaster
Because the RTC server has the current state of all of your checked in changes you can easily recreate your sandbox after a hard drive crash or accidental deletion. Repeat the setup steps above under "Setting up your environment," create a new sandbox, "cd" into the sandbox directory and load your repository workspace.
$ mkdir /Users/Chris/sandbox $ cd /Users/Chris/sandbox $ lscm load -r myserver MyMacWorkspace Successfully loaded items into the sandbox.
It is not recommended that you share your repository workspace with others. Using Jazz SCM with multiple users will be covered in the next article in this series. If you load your repository workspace in multiple locations your sandboxes can become out-of-sync, which is recoverable but may introduce complexities into your workflow. It is best at this stage to have a single sandbox and a single repository workspace for your work.
Add snapshots to organize history
Whenever significant events occur with your code you can create snapshots to record the state of your code at that point in time. For instance, you might want to create snapshots every time you run the unit tests to match the state of the code with the test results. Whenever you give someone a copy of the compiled application you could create a snapshot so that you know what changes are in their copy. However, you can only create a snapshot if all of your change sets are complete.
$ lscm create snapshot -n "Unit Tests Results: Failed" MyMacWorkspace Snapshot (1164) "Unit Tests Results: Failed" successfully created Baseline (1165) "Unit Tests Results: Failed" successfully included
If something unexpected occurs between when you build a copy of your application to one person and build another copy for someone else later on you can use these two points to find the change sets that occurred in between.
$ lscm list snapshots MyMacWorkspace ... (1178) "Snapshot before building for Bob" Jun 5, 2012 9:05 AM (1176) "Snapshot before building for Joe" Jun 7, 2012 8:59 AM ...
Now that you know the two snapshot aliases (1178 and 1176) you can compare them to discover the change sets that are in one but not the other. There is a good chance that the unexpected change is introduced in one of these change sets.
$ lscm compare snapshot 1178 snapshot 1176 Outgoing Changes Component (1136) "CoolXcodeProject" (1177) Chris McGee <cbmcgee@example.com> Performed a quick fix to the core util class 2012/06/05 Incoming Changes Component (1136) "CoolXcodeProject"
Let’s look inside this change set to see what files have changed. Then we’ll use the special scm-opendiff script to open up the differences in the Xcode difference viewer.
$ lscm list changes 1177 Change sets: (1177) ---$ Chris McGee "Performed a quick fix to the core util class" Component: (1136) "CoolXcodeProject" Modified: 05-Jun-2012 09:05 AM Changes: ---c- (1180) /MyXcodeProject/MyXcodeProject/Utils.m $ scm-opendiff MyXcodeProject/Utils.m 1177
The scm-opendiff tool brings up a Xcode’s graphical difference viewer and you can see what lines were changed in the file in this change set. You can use it whenever you have a change set alias and a file to see the change that is made.
Dive into the history
You can use snapshots to find change sets but if snapshots are not available then you can look at the history through a file or an entire component. This can be helpful if you are tracing a problem with a specific class or module back to its point of origin. Because change sets are such a pivotal part of Jazz SCM the history is shown in terms of change sets.
$ lscm history MyXcodeProjectTests.m Change sets: (1181) ---@ Chris McGee "Add a test for foo" 05-Jun-2012 10:17 AM (1182) ---$ Chris McGee "Add an inverse check to make sure that false is not true" 05-Jun-2012 09:57 AM (1177) ---$ Chris McGee "Added a simple boolean test" 05-Jun-2012 09:05 AM (1163) ---$ Chris McGee "Make the tests fail because there are none" 04-Jun-2012 04:50 PM (1139) ---$ Chris McGee "Fix the unit tests" 04-Jun-2012 02:47 PM (1138) ---$ Chris McGee "Share" 04-Jun-2012 02:30 PM ... OR ... $ lscm history (1181) ---@ Chris McGee "Add a test for foo" 05-Jun-2012 10:17 AM (1182) ---$ Chris McGee "Add an inverse check to make sure that false is not true" 05-Jun-2012 09:57 AM (1177) ---$ Chris McGee "Added a simple boolean test" 05-Jun-2012 09:05 AM (1163) ---$ Chris McGee "Make the tests fail because there are none" 04-Jun-2012 04:50 PM (1140) ---$ Chris McGee "Add the jazz ignore" 04-Jun-2012 02:51 PM (1139) ---$ Chris McGee "Fix the unit tests" 04-Jun-2012 02:47 PM (1138) ---$ Chris McGee "Share" 04-Jun-2012 02:30 PM (1166) ---$ Chris McGee "Initial for CoolXcodeProject" 04-Jun-2012 02:21 PM
The above example shows both the history of a particular file and the history of the entire component. Notice how the component history shows change sets that do not impact this file: the initial change set for the component and an add of a .jazzignore file.
Another great way to explore the history of the file is to print its annotated contents. The annotate command will display the current contents of the file along with the last change set that touched each line. Sometimes the change set will help to explain the rationale for why a certain check, assertion or function exists.
$ lscm annotate MyXcodeProjectTestSuite.m 1 Chris McGee (1181) 2012-06-05 10:17 AM Add a test for foo // 2 Chris McGee (1138) 2012-06-04 02:30 PM Share // MyXcodeProjectTests.m 3 Chris McGee (1138) 2012-06-04 02:30 PM Share // MyXcodeProjectTests 4 Chris McGee (1138) 2012-06-04 02:30 PM Share // 5 Chris McGee (1138) 2012-06-04 02:30 PM Share // Created by Chris McGee on 12-06-04. 6 Chris McGee (1138) 2012-06-04 02:30 PM Share // Copyright 2012 __MyCompanyName__. All rights reserved. 7 Chris McGee (1138) 2012-06-04 02:30 PM Share // ... 11 Chris McGee (1138) 2012-06-04 02:30 PM Share @implementation MyXcodeProjectTests 12 Chris McGee (1138) 2012-06-04 02:30 PM Share ... 27 Chris McGee (1177) 2012-06-05 09:05 AM Added a simple boole - (void)testBoolean 28 Chris McGee (1138) 2012-06-04 02:30 PM Share { 29 Chris McGee (1177) 2012-06-05 09:05 AM Added a simple boole STAssertTrue(true, @"True is false!"); 30 Chris McGee (1138) 2012-06-04 02:30 PM Share } ... 32 Chris McGee (1181) 2012-06-05 10:17 AM Add a test for foo - (void)testFoo ... 37 Chris McGee (1182) 2012-06-05 09:57 AM Add an inverse check - (void) testBar 38 Chris McGee (1182) 2012-06-05 09:57 AM Add an inverse check { 39 Chris McGee (1182) 2012-06-05 09:57 AM Add an inverse check STAssertFalse(false, @"False is True!"); 40 Chris McGee (1182) 2012-06-05 09:57 AM Add an inverse check } ... 42 Chris McGee (1138) 2012-06-04 02:30 PM Share @end ...
Suspend a change set to pause a work in progress, resume it to proceed
It was mentioned earlier that change sets can be discarded when they are no longer wanted. Sometimes a change set is simply left on hold for other more important work. It is still useful to have the repository workspace hold on to the changes but you want those changes taken away from your sandbox to avoid test failures or compile errors. This can be done by suspending your change set. Your change set does not need to be complete in order to suspend it.
$ lscm status Workspace: (1135) "MyMacWorkspace" <-> (1135) "MyMacWorkspace" Component: (1136) "CoolXcodeProject" Baseline: (1179) 3 "Unit Tests Result: Passed" Outgoing: Change sets: (1181) *--@ "Add a test for foo" 05-Jun-2012 09:37 AM $ lscm changeset suspend 1181 Change sets successfully suspended. $ lscm status Workspace: (1135) "MyMacWorkspace" <-> (1135) "MyMacWorkspace" Component: (1136) "CoolXcodeProject" Baseline: (1179) 3 "Unit Tests Result: Passed" Suspended: Change sets: (1181) ---@ "Add a test for foo" 05-Jun-2012 09:37 AM
Once a change set is suspended it will remain in your status under the "Suspended" section until you either resume it or discard it. You can use the lscm list changes and scm-opendiff tool on this changeset to refer back to the proposed changes. If you resume it after you have made other changes to the files then you will need to merge in the changes.
$ lscm changeset resume 1181 Resuming change sets: Repository: https://myserver:9443/jazz/ Workspace: (1135) "MyMacWorkspace" Component: (1136) "CoolXcodeProject" Change sets: (1181) --#@ "Add a test for foo" 05-Jun-2012 09:37 AM Changes: -#-c- /MyXcodeProject/MyXcodeProjectTests/MyXcodeProjectTests.m Problem running 'changeset resume': Conflicts in workspace after resume Run 'lscm resolve' or 'lscm conflicts' or 'lscm status' for help in resolving the conflicts. $ lscm status Workspace: (1135) "MyMacWorkspace" <-> (1135) "MyMacWorkspace" Component: (1136) "CoolXcodeProject" Baseline: (1179) 3 "Unit Tests Result: Passed" Conflicts: Cc- /MyXcodeProject/MyXcodeProjectTests/MyXcodeProjectTests.m (Modified <> Modified) Outgoing: Change sets: (1181) *--@ "Add a test for foo" 05-Jun-2012 09:37 AM
In this example the resume moved the change set from suspending to outgoing in the status. However, there is a conflict on MyXcodeProjectTests.m that needs to be resolved. For file content merges like this there is the scm-merge tool that will use Xcode’s own graphical merge tool to help you merge the changes. Once you have merged in all of the changes you can use the scm-resolve tool to resolve the conflicts and check them in.
$ scm-merge MyXcodeProjectTests/MyXcodeProjectTests.m ... <Merge changes manually using the Xcode merge GUI and save it using Cmd-S> ... $ scm-resolve MyXcodeProjectTests/MyXcodeProjectTests.m Workspace: (1135) "MyMacWorkspace" <-> (1135) "MyMacWorkspace" Component: (1136) "CoolXcodeProject" Baseline: (1179) 3 "Unit Tests Result: Passed" Outgoing: Change sets: (1181) *-#@ "Add a test for foo" 05-Jun-2012 10:17 AM Changes: -#-c- /MyXcodeProject/MyXcodeProjectTests/MyXcodeProjectTests.m
During the merge process local changes were made in your sandbox. The resolve process checked in those changes into a change set and marked the conflict as resolved. It is important to merge all of the changes together very carefully so that nothing is lost. Once you have finished the merge you should double check the file inside Xcode to make sure that the merge was successful and fix it up if necessary before running scm-resolve.
One really useful Jazz SCM pattern is to keep your application code changes in one change set and the unit test changes in another. When you have finished adding/changing your unit tests you can suspend the other change set to see if your new tests fail. Resume the change set to see if they pass.
Summary
In this article you saw how RTC can be used in conjunction with Xcode to both back up your work as well as keep detailed history of the changes. The Jazz SCM CLI has a rich set of commands that enable you to share your code to the server, recover from accidental loss of data, organize your changes into change sets and inspect the history of your code. Change sets can be suspended and resumed in order to put work on hold or even validate your unit tests.
The second part of this series of articles will begin to cover how to expand your project from a single contributor to multiple contributors using streams to flow your changes. You can use work items to begin tracking your bugs, tasks and enhancements.
For more information
About the author
Chris McGee is a member of the Jazz Source Control team. Previously, he worked on modeling tools for the Rational Software Architect project.
Copyright © 2012 IBM Corporation