Thanks for all the help. The final solution we implemented took a bit from every answer.
We found it easier to handle working with multiple environments using simple batch files. I'm not suggesting this is the best way to do this, but for our given scenario and requirements, this worked well. Supplement "Project" with your project name and "Environment" with your environment name (dev, test, stage, production, whatever).
Here is the tasks area of our "ccnet.config" file.
<!-- override settings -->
<exec>
<executable>F:\Source\Project\Environment\CruiseControl\CopySettings.bat</executable>
</exec>
<!-- compile -->
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe</executable>
<workingDirectory>F:\Source\Project\Environment\</workingDirectory>
<projectFile>Project.sln</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /v:diag</buildArgs>
<targets>Rebuild</targets>
<timeout>0</timeout>
<logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
<!-- clickonce publish -->
<exec>
<executable>F:\Source\Project\Environment\CruiseControl\Publish.bat</executable>
</exec>
The first thing you will notice is that CopySettings.bat runs. This copies specific settings for the environment, such as database connections.
Next, the standard MSBUILD task runs. Any compile errors are caught here and handled as normal.
The last thing to execute is Publish.bat. This actually performs a MSBUILD "rebuild" again from command line, and parameters from CruiseControl are automatically passed in and built. Next, MSBUILD is called for the "publish" target. The exact same parameters are given to the publish as the rebuild was issued. This keeps the build numbers in sync. Also, our executables are named differently (i.e. - ProjectDev and ProjectTest). We end up with different version numbers and names, and this allows ClickOnce to do its thing.
The last part of Publish.bat copies the actual files to their new homes. We don't use the publish.htm as all our users are on the network, we just give them a shortcut to the manifest file on their desktop and they can click and always be running the correct executable with a version number that ties out in CruiseControl.
Here is CopySettings.bat
XCOPY "F:\Source\Project\Environment\CruiseControl\Project\app.config" "F:\Source\Project\Environment\Project" /Y /I /R
XCOPY "F:\Source\Project\Environment\CruiseControl\Project\My Project\Settings.Designer.vb" "F:\Source\Project\Environment\Project\My Project" /Y /I /R
XCOPY "F:\Source\Project\Environment\CruiseControl\Project\My Project\Settings.settings" "F:\Source\Project\Environment\Project\My Project" /Y /I /R
And lastly, here is Publish.bat
C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe /target:rebuild "F:\Source\Project\Environment\Project\Project.vbproj" /property:ApplicationRevision=%CCNetLabel% /property:AssemblyName="ProjectEnvironment" /property:PublishUrl="\\Server\bin\Project\Environment\\"
C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe /target:publish "F:\Source\Project\Environment\Project\Project.vbproj" /property:ApplicationVersion="1.0.0.%CCNetLabel%" /property:AssemblyVersion="1.0.0.%CCNetLabel%" /property:AssemblyName="ProjectEnvironment"
XCOPY "F:\Source\Project\Environment\Project\bin\Debug\app.publish" "F:\Binary\Project\Environment" /Y /I
XCOPY "F:\Source\Project\Environment\Project\bin\Debug\app.publish\Application Files" "F:\Binary\Project\Environment\Application Files" /Y /I /S
Like I said, it's probably not done the way that CruiseControl and MSBUILD developers had intended things to work, but it does work. If you need to get this working yesterday, it might be the solution you're looking for. Good luck!