Monday, July 4, 2016

SVN Externals Application II

In the previous post, we checked out SVN Externals to build an XNA solution with the majority of game code written in an external library and scaled out across multiple game clients including Android + iOS.

As an example, the XNA and System Testing snake simulation was scaled to demonstrate SVN Externals.
However, all code here is in trunk; larger scale development requires release tags and feature branches. Let's check it out!

Pre Requisites
This post assumes you already have Tortoise SVN installed on Windows and svnx installed on Mac OS/X.
Also, consider configuring the $SVN_EDITOR on Windows and Mac OS/X in order to edit SVN properties:
set SVN_EDITOR=notepad.exe     ; Windows PC
export SVN_EDITOR=vi           ; Mac OS/X
Conventions
This post uses the following convention to substitute "$DEMO" for root node of all demo code samples:
$DEMO = https://svn/Demo       ; Subversion
$DEMO = C:\svn\Demo            ; Windows PC
$DEMO = /svn/Demo              ; Mac OS/X

Subversion
Create top level Demo node in Subversion SVN. Add 1x sub-node for XNA library and 4x sub-nodes for each client: WP7, Windows, Android, iOS. Ensure all sub-nodes have branches, tags and trunk folders:
 Alias  Platform  Development  Framework  Description  Source Code
 XNA  Windows PC  Visual Studio 2010  XNA 4.0  Game library  Download
 WP7  Windows PC  Visual Studio 2010  XNA 4.0  Game client  Download
 Win  Windows PC  Visual Studio 2012  MonoGame 3.4  Game client  Download
 And  Mac OS/X  Xamarin Studio  MonoGame 3.5  Game client  Download
 iOS  Mac OS/X  Xamarin Studio  MonoGame 3.5  Game client  Download

Tagging
Before beginning new development, it's often best practice to tag your current release build from trunk.

Note: when you create a tag in Subversion, you are not tagging the SVN Externals repository, you are tagging your working copy. If you do not specify the revision then SVN Update will always get latest!

Therefore, you should always explicitly set the revision of svn:externals property when you create a tag:
svn propset svn:externals 'Common -r2276 $DEMO/XNA/trunk/XNA.Common' .

If you have Tortoise SVN 1.9.4 installed then you can use the new --pin-externals option for svn copy. This will automatically set the SVN revision in the tag for you without manual lookup in the SVN logs.
svn copy --pin-externals svn:externals $DEMO/trunk $DEMO/tags/1.0.0.0 -m "1.0.0.0"

For completeness, here are all TAGS 1.0.0.0 cut from previous SVN Externals Application blog post:
 Alias  Command
 XNA  svn copy --pin-externals $DEMO/XNA/trunk $DEMO/XNA/tags/1.0.0.0-XNA -m "1.0.0.0-XNA"
 WP7  svn copy --pin-externals $DEMO/WP7/trunk $DEMO/WP7/tags/1.0.0.0-WP7 -m "1.0.0.0-WP7"
 Win  svn copy --pin-externals $DEMO/Win/trunk $DEMO/Win/tags/1.0.0.0-XNA -m "1.0.0.0-Win"
 And  svn copy --pin-externals $DEMO/And/trunk $DEMO/And/tags/1.0.0.0-And -m "1.0.0.0-And"
 iOS  svn copy --pin-externals $DEMO/iOS/trunk $DEMO/iOS/tags/1.0.0.0-iOS -m "1.0.0.0-iOS"

SVN Upgrade
On Mac OS/X it is most likely that you cannot use the new --pin-externals option for svn copy as the svn version is too low. Here are some basic instructions to upgrade to, for example, SVN 1.8 on Mac OS/X.

However, upgrading may cause svnx incompatibility. Also, higher versions may require an upgrade to serf. A better approach may be to cut all tags on Windows PC and SVN Update all tags on Mac OS/X.

Branching
Larger features usually require longer development time and it's often best practice to cut feature branch from trunk. Applying SVN Externals to branching and merging back into trunk may result in a similar flow:

 1. Cut branches: XNA library and Win client (and other clients)
 2. Update SVN Externals in Win client to XNA branch (not trunk)
 3. Make all code feature changes in XNA library and Win client
 4. Merge XNA library [trunk down to branch + branch up to trunk]
 5. Merge Win client [trunk down to branch + branch up to trunk]
 6. Delete dead branches cut from above accordingly

Implementation
1. Cut branches: XNA library and Win client (and other clients)
svn copy $DEMO/XNA/trunk $DEMO/XNA/branches/FeatureX -m "FeatureX"
svn copy $DEMO/Win/trunk $DEMO/Win/branches/FeatureX -m "FeatureX"

2. Update SVN Externals in Win client to XNA branch (not trunk)
Launch command prompt, navigate to $DEMO\Win\branches\FeatureX\$FOLDER where $FOLDER is the parent folder that hosts Windows Game project. Common branched XNA library code will be linked here.
cd $DEMO/Win/branches/FeatureX
svn propget -R svn:externals

cd $FOLDER
svn propedit svn:externals .
Edit SVN Externals Subversion Properties from previous to current:
 Previous  Current
 $DEMO/XNA/trunk/XNA.Common Common  $DEMO/XNA/branches/FeatureX/XNA.Common Common
svn update
svn commit -m "Update branch"

3. Make all code feature changes in XNA library and Win client
After making all code changes to feature branch, ensure you increment the build number for next release. Navigate to game client AssemblyInfo.cs file. Increment AssemblyVersion + AssemblyFileVersion values:

For example increment version from previous "1.0.0.0" to current "1.1.0.0"
 Platform  File  Property
 Android  AndroidManifest.xml  Increment Version number
 iOS  Info.plist  Increment Version
Note: updated version number should be synch'd in Xamarin Studio Project Options | Application tab


4. Merge XNA library [trunk down to branch + branch up to trunk]
First, merge trunk down to branch (as changes may have been checked-in on trunk prior to the merge)
cd $DEMO/XNA/branches/FeatureX
svn update
svn merge $DEMO/XNA/trunk
svn commit -m "Merge trunk down to branch"

Next, merge branch up to trunk to (re-)integrate changes from shared XNA library to all upstream clients
cd $DEMO/XNA/trunk
svn update
svn merge --reintegrate $DEMO/XNA/branches/FeatureX
svn commit -m "Merge branch up to trunk"

5. Merge Win client [trunk down to branch + branch up to trunk]
Important: first revert SVN Externals in Win client to XNA trunk as XNA trunk and branch are now synch'd
cd $DEMO/Win/branches/FeatureX
svn propget -R svn:externals

cd $FOLDER
svn propedit svn:externals .
Edit SVN Externals Subversion Properties from previous to current:
 Previous  Current
 $DEMO/XNA/branches/FeatureX/XNA.Common Common  $DEMO/XNA/trunk/XNA.Common Common
svn update
svn commit -m "Revert branch"

Next, merge trunk down to branch
cd $DEMO/Win/branches/FeatureX
svn update
svn merge $DEMO/Win/trunk
svn commit -m "Merge trunk down to branch"

Finally, merge branch up to trunk
cd $DEMO/Win/trunk
svn update
svn merge --reintegrate $DEMO/Win/branches/FeatureX
svn commit -m "Merge branch up to trunk"

6. Delete dead branches cut from above accordingly
svn delete $DEMO/XNA/branches/FeatureX -m "Delete branch"
svn delete $DEMO/Win/branches/FeatureX -m "Delete branch"

For completeness, here is one way to remove the SVN Externals property from working copy folder:
svn propdel svn:externals $DEMO/Win/branches/FeatureX/$FOLDER

Tagging
When it is appropriate, tag the new build as per updated build version number 1.1.0.0 from above:
 Alias  Command
 XNA  svn copy --pin-externals $DEMO/XNA/trunk $DEMO/XNA/tags/1.1.0.0-XNA -m "1.1.0.0-XNA"
 WP7  svn copy --pin-externals $DEMO/WP7/trunk $DEMO/WP7/tags/1.1.0.0-WP7 -m "1.1.0.0-WP7"
 Win  svn copy --pin-externals $DEMO/Win/trunk $DEMO/Win/tags/1.1.0.0-XNA -m "1.1.0.0-Win"
 And  svn copy --pin-externals $DEMO/And/trunk $DEMO/And/tags/1.1.0.0-And -m "1.1.0.0-And"
 iOS  svn copy --pin-externals $DEMO/iOS/trunk $DEMO/iOS/tags/1.1.0.0-iOS -m "1.1.0.0-iOS"


Summary
To summarize, here code has been shared from a single external library across multiple game clients; However, SVN Externals could be used to scale out shared data + content across multiple clients too!