I am using TFS 2008 and writing my builds using the built-in TeamBuild. I have the build set up in such a way that it will create a work item of type Bug upon failure, and will also create a bug upon unit test failure. However; today our build partially succeeded due to the fact that an exec task kicked off an executable which had a return code that was not 0.
My question then; is there some way to determine a partial succession of a build and create a bug work item based on that detection?
A snippet from the build .proj file in which I create a bug based on a failed unit test run:
<Target Name="AfterTest">
<!-- Refresh the build properties. -->
<GetBuildProperties TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
Condition=" '$(IsDesktopBuild)' != 'true' ">
<Output TaskParameter="TestSuccess" PropertyName="TestSuccess" />
</GetBuildProperties>
<!-- Set CompilationStatus to Failed if TestSuccess is false. -->
<SetBuildProperties TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
CompilationStatus="Failed"
Condition=" '$(IsDesktopBuild)' != 'true' and '$(TestSuccess)' != 'true' ">
</SetBuildProperties>
<CreateNewWorkItem BuildNumber="$(BuildNumber)"
BuildURi="$(BuildURI)"
Description="A failed test run caused the CreateNewWorkItem task created this bug. $(BuildlogText)"
TeamProject="$(TeamProject)"
TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
Title="Unit Test Failure in $(BuildNumber)"
WorkItemFieldValues="$(WorkItemFieldValues)"
WorkItemType="Bug"
Condition=" '$(IsDesktopBuild)' != 'true' and '$(TestSuccess)' != 'true' ">
</CreateNewWorkItem>
Any help would be greatly appreciated, thanks!
You could try to check for the error in another part of the build life cycle like
AfterDropBuild
You find the different targets to extend here
Related
Environment:
Windows 10 Home, 21H2
VS Version 17.3.0 Preview 1.1
I have followed these steps to get to this error:
Create a new VS project
Select .NET MAUI App
Choose a file location and leave everything else to default
Setting the project configuration file to this
<PropertyGroup>
<TargetFrameworks>net6.0-android;net6.0-ios;net6.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net6.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net6.0-tizen</TargetFrameworks> -->
<OutputType>Exe</OutputType>
<RootNamespace>MauiApp1</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Display name -->
<ApplicationTitle>MauiApp1</ApplicationTitle>
<!-- App Identifier -->
<ApplicationId>com.testapp.maui</ApplicationId>
<ApplicationIdGuid>CE4B9160-2B17-4559-8E4C-EA410A9A7966</ApplicationIdGuid>
<!-- Versions -->
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">14.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<RuntimeIdentifier>ios-arm64</RuntimeIdentifier>
<CodesignKey>Apple Distribution: My Name (xxxxxxx)</CodesignKey>
<CodesignProvision>Apple Provisioning</CodesignProvision>
<ArchiveOnBuild>true</ArchiveOnBuild>
<TcpPort>58181</TcpPort>
<ServerAddress>xxxxx</ServerAddress>
<ServerUser>xxxxx</ServerUser>
<ServerPassword>xxxxx</ServerPassword>
<_DotNetRootRemoteDirectory>/Users/xxxxx/Library/Caches/Xamarin/XMA/SDKs/dotnet/</_DotNetRootRemoteDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net6.0-ios|AnyCPU'">
<BuildIpa>True</BuildIpa>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0-ios|AnyCPU'">
<BuildIpa>True</BuildIpa>
</PropertyGroup>
<ItemGroup>
<!-- App Icon -->
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
<!-- Splash Screen -->
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
<!-- Images -->
<MauiImage Include="Resources\Images\*" />
<MauiImage Update="Resources\Images\dotnet_bot.svg" BaseSize="168,208" />
<!-- Custom Fonts -->
<MauiFont Include="Resources\Fonts\*" />
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
Connect to the build Mac
Test run on Windows as Windows app, successful.
Run this command
dotnet publish -f:net6.0-ios -c:Release
Error
iOS code signing key '?Apple Distribution: My Name (xxxxxx)' not found
in keychain.
I've also tried doing a Release build through VS GUI (Right click on Solution -> Rebuild), then I get this error:
Code signing must be enabled to create an Xcode archive.
Previous to that
I executed step by step according to this https://github.com/dotnet/maui/issues/4397 and this https://www.youtube.com/watch?v=kpZi5xAvpZA
Did all the necessary steps in my Apple Developer Account
Installed the certificate in the keychain on a Mac
Installed the provisioning file in XCode
Initially my certificate in the keychain on the Mac showed invalid/not trusted. After doing this https://stackoverflow.com/a/65120256/5909367 it shows valid
Also notice, there is a question mark in the error '?Apple Distribution: My Name (xxxxxx)', which I don't know where it's coming from.
Update:
I used this command to create a log file during the build
dotnet publish -f:net6.0-ios -c:Release /bl:msbuild.binlog
The logfile can be viewed with this tool: https://msbuildlog.com/
In this logfile, the error message does not have the question mark. So I guess the question mark is just a display error when writing the log message.
In the binlog then, it literally says this:
The certificate 'Apple Distribution: My Name (xxx)' does not match
'Apple Distribution: My Name (xxx)'.
I have checked character for character. It is exactly the same string.
I also have noticed, that it does download the certificates from the server, because I can see them listed in the binlog after the entry "DetectingSigningIdentity"
I figured it out, thanks to the last comment!
The string
<CodesignKey>Apple Distribution: My Name (xxx)</CodesignKey>
contains a hidden character. I can't reproduce this in this post, because the hidden characters get filtered out.
But it can be reproduced with a string to hex converter: https://online-toolz.com/tools/text-hex-convertor.php
Type in this hex code: 3ee2808c and it will produce this character "<". When you type 3e, it will produce the same character "<". The problem is when copy/pasted, hidden characters come with it.
To prove this you can simply copy/paste the "<" from the first product into the tool again.
Looking up the character "e2808c", it stands for a "Zero-width non-joiner" https://en.wikipedia.org/wiki/Zero-width_non-joiner https://www.fileformat.info/info/unicode/char/200c/index.htm
How this got into the string, I don't know. I also didn't know that there can be hidden characters in strings!
So then one of these hidden strings got into my CodesignKey tag, and it would not match anymore. Visual Studio pointed this out correctly with a question mark. But my interpretation of the error was wrong, because I didn't expect something to be there that I can not see....
I'm stuck in a scenario where my published file is initially correct, but then later is replaced by it's original version. I suspect that the order of events is wrong, coupled with what's in the root directory.
Essentially I have successfully setup my publishing environment where it executes a custom command to create some JavaScript (which gets created outside of my project). Because a file in source control needs to reference this newly created JavaScript, I am simply copying the file (MyControl.ascx) to a temp location (thus it loses the read lock by TFS) and I am having the custom command update the references to the JS. Once this is done, I gather all the files (custom JavaScript, as well as edited MyControl.ascx in it's temp location) and publish.
It publishes everything first, so I see the new JS as well as the updated MyControl.ascx, but a few minutes later it finishes the publish, and Control looks like how it looked in the root directory.
I think what's happening is it's just pushing out what's in the root (which includes MyControl.ascx) on top of my custom Control (which is in another directory).
<PropertyGroup>
<PipelineCollectFilesPhaseDependsOn>
CustomCollectFiles;
$(PipelineCollectFilesPhaseDependsOn);
</PipelineCollectFilesPhaseDependsOn>
</PropertyGroup>
<Target Name="CustomCollectFiles">
Exec Command="MyCommand.bat"
<ItemGroup>
<_BundledJS Include="$(MSBuildThisFileDirectory)..\..\Includes\javascript\*.js" />
<FilesForPackagingFromProject Include="%(_BundledJS.Identity)">
<DestinationRelativePath>Includes\javascript\%(Filename)%(Extension)
</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
<ItemGroup>
<_UpdatedControl Include="$(MSBuildThisFileDirectory)..\..\TempArea\MyControl.ascx" />
<FilesForPackagingFromProject Include="%(_UpdatedControl.Identity)">
<DestinationRelativePath>Controls\%(Filename)%(Extension)
</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
So you can see above i'm taking something that's in ....\TempArea\MyControl.ascx and pushing it out to Controls\%(Filename)%(Extension).
Any ideas how I can tell it to essentially retain my ....\TempArea\MyControl.ascx without then overwriting it with the original MyControl.ascx within the project (....\Controls\MyControl.ascx) ?
Thanks so much!
So I actually ended up figuring it out, and wanted to share:
<ItemGroup>
<_UpdatedControl Include="$(MSBuildThisFileDirectory)..\..\TempArea\MyControl.ascx" />
<FilesForPackagingFromProject Remove="Controls\MyControl.ascx" ></FilesForPackagingFromProject>
<FilesForPackagingFromProject Include="%(_UpdatedControl.Identity)" >
<DestinationRelativePath>Controls\%(RecursiveDir)%(Filename)%(Extension) </DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
So you can see here it actually removes the original control, then adds it back.
I also changed the target as such:
<PropertyGroup>
<OnAfterPipelineCollectFilesPhase>
CustomCollectFiles;
$(OnAfterPipelineCollectFilesPhase);
</OnAfterPipelineCollectFilesPhase>
</PropertyGroup>
Let me know if any questions would be happy to help!
I've got a handy visual studio external tool shortcut to build the current project with MvcBuildViews enabled.
Arguments: /m:2 $(ProjectFileName) /p:MvcBuildViews=true
Command Line: C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe /m:2 "ProviderPortal.csproj" /p:MvcBuildViews=true
Anytime there is an error on a view, it stops at that one and reports it.
I want to know all the views that have errors not just stop at the first one.
How would I tell the Aspnet-Compiler to continue on errors? Or is there a way to get msbuild to instead invoke the aspnet-compiler per view rather than a one-shot call?
You can try setting ContinueOnError to ErrorAndContinue:
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" ContinueOnError="ErrorAndContinue" />
</Target>
http://msdn.microsoft.com/en-us/library/ms171484.aspx
I'm using ant to build my app, and I want to have single process for dev/qa/prod versions of the app. I want to do be able to specify the build target from command line:
ant -Dbuildtarget=dev|qa|prod
and in build.xml check for the value of buildtarget and set an application specific base URL property based on the buildtarget specified by the user. I will subsequently set the correct runtime param using
<copy file="pre.app.properties" tofile="./app.properties" overwrite="true">
<filterset>
<filter token="BASE_URL" value="${baseurl}" />
</filterset>
</copy>
What I am stuck on is how to express this in and build.xml ?
if buildtarget=='dev'
baseurl="http://my_dev_url"
else if buildtarget=='qa'
baseurl="http://my_qa_url"
else if buildtarget=='prod'
baseurl="http://my_prod_url"
I've searched around, but this seems to be difficult to do in ant. Any ideas ?
When starting your ant script with ant -Dbuildtarget=dev|qa|prod it's as simple as =
<project >
<property name="baseurl" value="http://my_${buildtarget}_url"/>
<echo>$${baseurl} => ${baseurl}</echo>
</project>
The buildtarget property can be used as dynamic part of the baseurl property.Afterwards ${buildurl} can be used for further processing..
Perhaps you should try using the condition task of ant?
We have TFS 2008 our build set up to checkout all AssemblyInfo.cs files in the project, update them with AssemblyInfoTask, and then either undo the checkout or checkin depending on whether the build passed or not. Unfortunately, when two builds are queued close together this results in a Partially completed build as the AssemblyInfo.cs files seem to be checked out at an earlier version to the previous checkin.
In order to get around this I thought that I could use the "Get" task to force the AssemblyInfo.cs files to the latest version before updating them, but this appears to have no effect. Any ideas?
<Target Name="AfterGet" Condition="'$(IsDesktopBuild)'!='true'">
<Message Text="SolutionRoot = $(SolutionRoot)" />
<Message Text="OutDir = $(OutDir)" />
<!-- Set the AssemblyInfoFiles items dynamically -->
<CreateItem Include="$(SolutionRoot)\Main\Source\InputApplicationSln\**\$(AssemblyInfoSpec)">
<Output ItemName="AssemblyInfoFiles" TaskParameter="Include" />
</CreateItem>
<Message Text="$(AssemblyInfoFiles)" />
<!-- When builds are queued up successively, it is possible for the next build to be set up before the AssemblyInfoSpec is checked in so we need to force
the latest these versions of these files to be got before a checkout -->
<Get Condition=" '$(SkipGet)'!='true' " TeamFoundationServerUrl="$(TeamFoundationServerUrl)" Workspace="$(WorkspaceName)" Filespec="$(AssemblyInfoSpec)" Recursive="$(RecursiveGet)" Force="$(ForceGet)" />
<Exec WorkingDirectory="$(SolutionRoot)\Main\Source\InputApplicationSln"
Command="$(TF) checkout /recursive $(AssemblyInfoSpec)"/>
Does your build re-write the AssemblyInfo files and then check them back in? Or do you just modify the AssemblyInfo files locally. Personally I prefer the latter approach - as documented over at the TFSBuild recipies site:
http://tfsbuild.com/AssemblyVersioning%20.ashx
I've never actually sat down and checked but I was wondering if you checked in the AssemblyInfo files then could the following be happening which might be causing your problems...
Request a build, current changeset = 42
Build 1 for changeset 42 starts running
Request a build, current changeset = 42 (still)
Build 2 for changeset 42 queued
Build 1 checks in new assemblyinfo files, current changeset = 43
Build 1 completes
Build 2 for changeset 42 starts, dows a get of changeset 42 meaning AssemblyInfo files are the fold ones.
As I say, not exactly sure when the changeset number is determined for the build - at the time of queuing or at the time of running. It would make more sense for it to be at the time of queueing though.
Changing:
<Get Condition=" '$(SkipGet)'!='true' " TeamFoundationServerUrl="$(TeamFoundationServerUrl)" Workspace="$(WorkspaceName)" Filespec="$(AssemblyInfoSpec)" Recursive="$(RecursiveGet)" Force="$(ForceGet)" />
To:
<Get Condition=" '$(SkipGet)'!='true' " TeamFoundationServerUrl="$(TeamFoundationServerUrl)" Workspace="$(WorkspaceName)" Filespec="$(AssemblyInfoSpec)" Recursive="True" Force="True" />
Has forced the AssemblyInfo.cs files to be overwritten with top of tree. It's been working so far, but is more of a hack than something elegant.