I have added a MSBuild target to update the PublishUrl and then call the 'Publish' target, passing the new value in. This has allowed me to build multiple branches and have the corresponding ClickOnce app dropped in a branch specific share location.
<PropertyGroup>
<PublishUrl >\\someNetworkShare\</PublishUrl>
</PropertyGroup>
<Target Name="PublishClickOnce">
<PublishUrl>$(PublishUrl)$(BranchName)\</PublishUrl>
<MSBuild Projects="$(ProjectPath)" Properties="PublishUrl=$(PublishUrl); PublishDir=$(PublishUrl); Platform=AnyCPU" Targets="Publish" />
</Target>
The problem is that this just doesn't work on one of my build machines. It works perfectly fine on 2 of them, but not the 3rd.
Looking at the myApp.application file i can see that the deploymentProvider codebase points to the unchanged PublishedUrl (but it has been updated at the time of calling the 'Publish' target:
<deploymentProvider codebase="file://someNetworkShare/myApp.application" />
The above should be:
<deploymentProvider codebase="file://someNetworkShare/branchName/myApp.application" />
A few things i have tried:
Update the 'InstallUrl' to match the 'PublishUrl'
Added logging to ensure that the 'PublishUrl' has updated before calling the 'Publish' target.
Added a condition to the 'PublishUrl' to only update if it is empty
Any help would be much appreciated.
Thanks
-------------------------------- UPDATE --------------------------------
So a couple of things:
The working build machines are on W7, the failing machines are on a mixture of W7 and W8.
It turns out that you can exclude the deploymentProvider element (ProjectProperties -> Publish -> Manifest -> Exclude deployment provider URL). If excluded the system attempts to figure it out by its self at run-time (this is sufficient in most cases).
So I tested the build on a few more machines (a completely clean W7 VM, a W7 dev machine, W8.1 dev machine) and they both produced the incorrect deploymentProvider line.
Still curious to the actual root cause of the issue so I don't want to mark it as answered.
Related
We are using Microsoft's Release Management tool for automating the deployment of our solution to our various dev servers. This tool is ideal for us because it can perform more complicated deployments that span multiple servers. In this sense, it is working fine and everything is deploying correctly.
A minor issue is that after Release Management automatically deploys a build, it sets the build to "Retain Indefinitely" which is indicated by the Lock icon. Since we are doing continuous deployment, we are retaining a large number of builds and the Build Definition's retention policy is overridden. I therefore have to go in periodically and highlight all of the previous builds and unselect Retain Indefinitely.
Because we are not deploying past dev with Release Management (we unfortunately aren't allowed to), we don't need to keep all of these dev builds around.
Is there a way to change Release Management so that it doesn't set builds to Retain Indefinitely?
Update: Since this is not currently possible, if you would like this feature, please vote for it on UserVoice: https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/6537614-allow-retain-indefinitely-to-not-be-set
As of RM for TFS 2013.3, this is not possible. According to Teodora Stanev on this post, this is by design.
Feel free to post a request on the Visual Studio UserVoice site
I have a solution to this, rather a workaround.
I have customized our build definition with the following Sequence (for TFS 2013) at the beginning of the workflow. This sequence grabs all succeeded builds for the definition and clears the Retain Indefinitely.
This means only the last ran build will have the flag. It also means you can't set a build as retain indefinitely for that definition. That is OK for us in this specific situation as it is for continuous integration builds (like the poster).
Edit: Changing to include All builds (was Successful only) as a build is marked as failed and still set to retain indefinitely if the build succeeds but release fails.
<Sequence DisplayName="Cleanup: Clear 'Retain Indefinitely' from previous builds">
<Sequence.Variables>
<Variable x:TypeArguments="mtbc:IBuildDetail" Name="localBuildDetail" />
<Variable x:TypeArguments="mtbc:IBuildDetailSpec" Name="localBuildDetailSpec" />
<Variable x:TypeArguments="mtbc:IBuildQueryResult" Name="localBuildQueryResult" />
</Sequence.Variables>
<mtbwa:GetBuildDetail DisplayName="Get the Build Details" Result="[localBuildDetail]" />
<InvokeMethod DisplayName="Create the Build Detail Spec" MethodName="CreateBuildDetailSpec">
<InvokeMethod.TargetObject>
<InArgument x:TypeArguments="mtbc:IBuildServer">[localBuildDetail.BuildServer]</InArgument>
</InvokeMethod.TargetObject>
<InvokeMethod.Result>
<OutArgument x:TypeArguments="mtbc:IBuildDetailSpec">[localBuildDetailSpec]</OutArgument>
</InvokeMethod.Result>
<InArgument x:TypeArguments="x:String">[localBuildDetail.TeamProject]</InArgument>
</InvokeMethod>
<Assign DisplayName="Setting Query Order Descending">
<Assign.To>
<OutArgument x:TypeArguments="mtbc:BuildQueryOrder">[localBuildDetailSpec.QueryOrder]</OutArgument>
</Assign.To>
<Assign.Value>
<InArgument x:TypeArguments="mtbc:BuildQueryOrder">FinishTimeDescending</InArgument>
</Assign.Value>
</Assign>
<Assign DisplayName="Setting Build Definition">
<Assign.To>
<OutArgument x:TypeArguments="x:String">[localBuildDetailSpec.DefinitionSpec.Name]</OutArgument>
</Assign.To>
<Assign.Value>
<InArgument x:TypeArguments="x:String">[localBuildDetail.BuildDefinition.Name]</InArgument>
</Assign.Value>
</Assign>
<Assign DisplayName="Setting Query Type to All Builds">
<Assign.To>
<OutArgument x:TypeArguments="mtbc:BuildStatus">[localBuildDetailSpec.Status]</OutArgument>
</Assign.To>
<Assign.Value>
<InArgument x:TypeArguments="mtbc:BuildStatus">All</InArgument>
</Assign.Value>
</Assign>
<InvokeMethod DisplayName="Getting Previous Builds" MethodName="QueryBuilds">
<InvokeMethod.TargetObject>
<InArgument x:TypeArguments="mtbc:IBuildServer">[localBuildDetail.BuildServer]</InArgument>
</InvokeMethod.TargetObject>
<InvokeMethod.Result>
<OutArgument x:TypeArguments="mtbc:IBuildQueryResult">[localBuildQueryResult]</OutArgument>
</InvokeMethod.Result>
<InArgument x:TypeArguments="mtbc:IBuildDetailSpec">[localBuildDetailSpec]</InArgument>
</InvokeMethod>
<ForEach DisplayName="Loop through all builds and undo 'Retain Indefinitely' set by Release Management."
x:TypeArguments="mtbc:IBuildDetail"
Values="[localBuildQueryResult.Builds]">
<ActivityAction x:TypeArguments="mtbc:IBuildDetail">
<ActivityAction.Argument>
<DelegateInArgument x:TypeArguments="mtbc:IBuildDetail" Name="localBuild" />
</ActivityAction.Argument>
<Sequence DisplayName="Checking Build Next Build">
<If Condition="[localBuild.KeepForever = True]" DisplayName="If the build is marked 'Retain Indefinitely'">
<If.Then>
<Sequence DisplayName="Updating Build Details">
<Assign DisplayName="Setting KeepForver to false">
<Assign.To>
<OutArgument x:TypeArguments="x:Boolean">[localBuild.KeepForever]</OutArgument>
</Assign.To>
<Assign.Value>
<InArgument x:TypeArguments="x:Boolean">false</InArgument>
</Assign.Value>
</Assign>
<InvokeMethod DisplayName="Saving Build Details" MethodName="Save">
<InvokeMethod.TargetObject>
<InArgument x:TypeArguments="mtbc:IBuildDetail">[localBuild]</InArgument>
</InvokeMethod.TargetObject>
</InvokeMethod>
</Sequence>
</If.Then>
</If>
</Sequence>
</ActivityAction>
</ForEach>
</Sequence>
Release Management follows the model of Lab Management, whereby if a Build is deployed it is retained indefinately.
This allows you to alter the build quality etc as the build is verified and signed off, you may then promote / do whatever with that build without fear that it will be deleted by the retention policy.
you just need to do it as a daily / weekly / monthly admin task, choose your build from the drop down list in the build screen and then show all.
highlight all of the builds and then click the remove retention button.
if it bothers you that much you could write a script to find all of the builds and then remove the lock.
psudo:
BuildDefinition.KeepForever = False;
For some specific purpose, I need to install some fonts on the instances. It comes as no surprise when I choose StartUp Task to accomplish that goal. I've configured the Service Definitions as below:
<Startup>
<Task commandLine="Fonts\InstallFonts.vbs" executionContext="elevated" taskType="simple" />
</Startup>
Nothing special here. Click and run, it failed. However, if I changed the commandLine into a cmd file including just nonsense, namely "echo test", the instance would run without ado. So there must be some issue with my scripting:
Const FONTS = &H14&
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.Namespace(CreateObject("Scripting.FileSystemObject").GetAbsolutePathName("."))
Set fontFolder = objShell.Namespace(FONTS)
Set rxTTF = New RegExp
rxTTF.IgnoreCase = True
rxTTF.Pattern = "\.ttf$"
Set fso = CreateObject("Scripting.FileSystemObject")
FOR EACH FontFile IN objFolder.Items()
IF rxTTF.Test(FontFile.Path) THEN
IF NOT fso.FileExists(fontFolder.Self.Path+"\\"+FontFile.Name) THEN
FontFile.InvokeVerb("Install")
END IF
END IF
NEXT
The script should come with no error because I've tested it either locally or on Azure via RDP.
Weirdly, when I put it in the startup, the role just won't start. The instance just keeps recycling and at last says "I'm unhealthy". Even if I deprecate the vbs into just one line of code - the first line Const FONTS = &H14&, it just won't start. Even if I wrap the invocation of the vbs into a cmd file, namely to put something like "cscript /B file.vbs", it won't run either.
So I'm concluding that there must be some issue regarding the communication between the script and the Windows Azure monitor. I'm not sure but I think the monitor might take the running script as a failed task. Besides, I'm wondering if there is any timeout for the startup task, which should be the problem though, because the script can guarantee that no UI interaction block the process.
Any idea would be greatly appreciated.
I am sure you must have but just for the sake of confirmation, have you checked that the InstallFonts.vbs file is exported with the package? I mean is the "Copy To Output Directory" is set to "Copy Always/Copy if newer"?
This is pretty much possible that it is not able to locate your file.
You need to write a cmd file as a start up task. In your cmd file, you can call the vbs file using the command line tool cscript.
Azure start up can compile only command line tools.
Oh god, I finally solved the problem.
Although the compiler does quite a good job usually, it allows to use subfolder as a source of command, I mean something like "Subfolder\command.cmd", which will not work always. I've seen examples in which people put whatever we do in cmd in commandLine property, such as "copy fileA fileB" and it really works. But as for vbs, you need to be cautious. Until now I still don't know what's under the cover, but there should be some problem with the path. And the solution is definitely simple, instead of doing the subfolder work for tidiness, just leave the command file in the root folder like most people do:
<Startup>
<Task commandLine="InstallFonts.vbs" executionContext="elevated" taskType="simple" />
</Startup>
And thank you all the same, Kunal. :)
I have a target, comprised of several steps, that sometimes fails. All this target does is report to Sonar so if it fails, it's not catastrophic. How do I get the build to succeed even if this specific target fails?
I've tried some combinations of 'condition', 'or', 'true', and 'sequential', but Ant hasn't liked any of them.
Following is what I have more or less:
<target name='sonar'>
<!-- do some stuff -->
<sonar:sonar key='key' version='version'/>
</target>
The only way I can see this could work is using the slightly outdated yet still useful antcontrib extension. Then you can use a try/catch directive and just echo your error.
http://ant-contrib.sourceforge.net/tasks/tasks/trycatch.html
I have a tfs 2008 build that I need to add WiX compliation to.
Currently the build executes and compiles and copies all output to a drops location in the following target
<Target Name="AfterCompile"> .... </Target>
I have added another target directly below it that looks like the following
<UsingTask TaskName="HeatDirectory" AssemblyFile="$(WixTasksPath)" />
<Target Name="BuildMsi" DependsOnTargets="AfterCompile">
<Message Text="Start harvesting Website files for Wix compliation" />
<HeatDirectory
ToolPath="$(WixToolPath)"
Directory="$(DropLocation)\Latest\x86\Release\_PublishedWebsites\IFMA.MasterPlan.Web"
GenerateGuidsNow="yes"
ComponentGroupName="Web"
OutputFile="$(MSBuildProjectDirectory)\Setup\Product\Fragments\wwwfiles.wxs"
SuppressFragments="yes"
DirectoryRefId="WebRoot"
KeepEmptyDirectories="yes"
PreprocessorVariable="var.WebRoot"
SuppressRegistry="yes"
SuppressRootDirectory="yes"
SuppressCom="yes"
/>
<Message Text="Finished harvesting Website files for Wix compliation" />
</Target>
The BuildMsi target is never executed but the AfterCompile one definitly is.
The BuildMsi isn't listed in the default build targets
but I thought that since it has a dependency on AfterCompile it would be executed after it.
What am I missing here?
DependsOnTargets lists the targets that must be executed before your target can run, it does not force your target to run after the list of targets run.
See: http://msdn.microsoft.com/en-us/library/t50z2hka(v=VS.90).aspx
If you're using MSBuild 4.0, AfterTargets attribute is what you need:
AfterTargets: Optional attribute.
A semicolon-separated list of target
names. When specified, indicates that
this target should run after the
specified target or targets. This
lets the project author extend an
existing set of targets without
modifying them directly.
Alternatively you can use target injection, which basically is overriding the CompileDependsOn property in your .proj file to include your target at the end. You need to declare this property after the imports of the common target files to ensure it is the last definition of the property.
<PropertyGroup>
<CompileDependsOn>
$(CompileDependsOn);
MyCustomTarget
</CompileDependsOn>
</PropertyGroup>
See "How to extend the visual studio build process" for more details.
How would you manually trigger additional team builds from a team build? For example, when we were in CC.Net other builds would trigger if certain builds were successful. The second build could either be projects that use this component or additional, long running test libraries for the same component.
One way you could do it is you could an an AfterEndToEndIteration target to your TFSBuild.proj file that would runs the TfsBuild.exe command line to start you other builds. I'm thinking something like this (though I haven't tested it)
<Target Name="AfterEndToEndIteration">
<GetBuildProperties TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
Condition=" '$(IsDesktopBuild)' != 'true' ">
<Output TaskParameter="Status" PropertyName="Status" />
</GetBuildProperties>
<Exec Condition=" '$(Status)'=='Succeeded' "
Command="TfsBuild.exe start /server:$(TeamFoundationServerUrl) /buildDefinition:"Your Build Definition To Run"" />
</Target>
I've done the same thing Martin suggested on a number of occasions (his blog is beyond helpful, BTW). However, I ended up needing to trigger cascading builds like this (based on some other complicated rules) enough that I created a custom task to do it. Keep your build scripts nice and lean and gives you some more flexibility and encapsulation possibilities.
public override bool Execute()
{
IBuildDefinition[] buildDefinitions = BuildServer.QueryBuildDefinitions(ProjectName);
foreach (IBuildDefinition build in buildDefinitions)
{
if(build.Enabled) //I did a bunch of custom rules here
{
Log.LogMessage(String.Concat("Queuing build: ", build.Name));
BuildServer.QueueBuild(build);
}
}
return true;
}
There's some more good stuff on Aaron Hallberg's blog too:
http://blogs.msdn.com/aaronhallberg/archive/2007/04/24/team-build-object-model-queueing-a-build.aspx