views:

3515

answers:

6

I have CruiseControl.NET Version 1.4 set up on my development server. Whenever a developer checks in code, it makes a compile.

Now we're at a place where we can start giving our application to the testers. We'd like to use ClickOnce to distribute the application, with the idea being that when a tester goes to test the application, they have the latest build.

I can't find a way to make that happen with CruiseControl.NET. We're using MSBUILD to perform the builds.

A: 

You want to use the ClickOnce manifest generation tasks in msbuild. The process is a little long winded, so I am just going to point you to a couple of links. Here is the reference on msdn and a sample article to hopefully get you started.

Dale Ragan
+14  A: 

We've done this and can give you some pointers to start.

2 things you should be aware of:

  • MSBuild can generate the necessary deployment files for you.
  • MSBuild won't deploy the files to the FTP or UNC share. You'll need a separate step for this.

To use MSBuild to generate the ClickOnce manifests, here's the command you'll need to issue:

msbuild /target:publish /p:Configuration=Release /p:Platform=AnyCPU; "c:\yourProject.csproj"

That will tell MSBuild to build your project and generate ClickOnce deployment files inside the bin\Release\YourProject.publish directory.

All that's left is to copy those files to the FTP/UNC share/wherever, and you're all set.

You can tell CruiseControl.NET to build using those MSBuild parameters.

You'll then need a CruiseControl.NET build task to take the generated deployment files and copy them to the FTP or UNC share. We use a custom little C# console program for this, but you could just as easily use a Powershell script.

Judah Himango
+3  A: 

I remember doing this last year for a ClickOnce project I was working on. I remember it taking me forever to figure out but here it is. What I wanted my scripts to do was to generate a different installer that pointed to our dev env and a different one for prod. Not only that but i needed it to inject the right versioning information so the existing clients would 'realize' there is a new version out there which is the whole point of clickOnce. In this script you have to replace with your own server names etc. The trick is to save the publish.htm and project.publish file and inject the new version number based on the version that is provided to you by CC.NET.

Here is what my build script looked like:

<target name="deployProd">
  <exec program="<framework_dir>\msbuild.exe" commandline="<project>/<project>.csproj /property:Configuration=PublishProd /property:ApplicationVersion=${build.label}.*;PublishUrl=\\<prod_location>\binups$\;InstallUrl=\\<prod_location>\binups$\;UpdateUrl=\\<prod_location>\binups$\;BootstrapperComponentsUrl=\\<prod_location>\prereqs$\ /target:publish"/>

  <copy todir="<project>\bin\PublishProd\<project>.publish">

    <fileset basedir=".">
      <include name="publish.htm"/>
    </fileset>

    <filterchain>
      <replacetokens>
        <token key="CURRENT_VERSION" value="${build.label}"/>
      </replacetokens>
     </filterchain>
  </copy>

</target>

Hope this helps

fnCzar
A: 

Hi. Anyone notice differences in the publish directory, building a sln from the IDE vs msbuild? I’m getting some dll’s in different locations (with msbuild is in the root and with the IDE is in bin).

+7  A: 

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!

proudgeekdad
A: 

Just be able passing the ${CCNetLabel} in the CCNET.config msbuild task would be a great improvement.