<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>MSBuild &#8211; BeatificaBytes</title>
	<atom:link href="https://www.BeatificaBytes.be/tag/msbuild/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.BeatificaBytes.be</link>
	<description>The Joys of Computing</description>
	<lastBuildDate>Sat, 27 Oct 2012 17:07:10 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8</generator>
	<item>
		<title>Drop Builds&#8217; primary output in a &#8220;Latest&#8221; folder</title>
		<link>https://www.BeatificaBytes.be/drop-the-primary-output-of-builds-in-a-latest-folder/</link>
					<comments>https://www.BeatificaBytes.be/drop-the-primary-output-of-builds-in-a-latest-folder/#respond</comments>
		
		<dc:creator><![CDATA[vletroye]]></dc:creator>
		<pubDate>Sat, 27 Oct 2012 17:07:10 +0000</pubDate>
				<category><![CDATA[TFS]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[MSBuild]]></category>
		<category><![CDATA[Team Build]]></category>
		<guid isPermaLink="false">/wordpress/?p=478</guid>

					<description><![CDATA[As briefly mentioned in another post, we have a specific &#8220;Reference Assemblies&#8221; folder on the Build Machines containing the latest version of each assembly issued [&#8230;]]]></description>
										<content:encoded><![CDATA[<p style="text-align: justify">As briefly mentioned <a title="Support for Multiple Target Environments on a Single Build Machine" href="https://www.beatificabytes.be/target-multiple-environments-with-only-one-tfs-build-server/" target="_blank" rel="noopener noreferrer">in another post</a>, we have a specific &#8220;Reference Assemblies&#8221; folder on the Build Machines containing the latest version of each assembly issued from a successful Build. Assemblies in that folder, know as the &#8220;Latest&#8221; folder, can be used for &#8220;<em>Continuous Integration</em>&#8221; Builds.  This post is about the <em>pragmatic</em> solution implemented to drop only the primary output of the Builds in that folder.</p>
<p style="text-align: justify"><span class="collapseomatic " id="id69b523b8c7c07"  tabindex="0" title="Click to Read More"    >Click to Read More</span><span id='swap-id69b523b8c7c07'  class='colomat-swap' style='display:none;'>Click to Close</span><div id="target-id69b523b8c7c07" class="collapseomatic_content ">
<p style="text-align: justify">The output of a Build contains not only the assemblies and satellite assemblies issued from the compilation of the Visual Studio Projects (I.e.: assemblies part of the &#8220;primary output&#8221; as named in the Microsoft Setup Projects). It contains also a copy of all the referenced assemblies (file references) with the property &#8220;CopyLocal&#8221;=&#8221;True&#8221;.</p>
<p style="text-align: justify">It&#8217;s important for our purpose to only drop the primary output into the &#8220;Latest&#8221; folder, otherwise we could override the latest version of some referenced assemblies with a  copy of the specific version found for the Build (e.g.: when targeting the Integration Environment, we use the promoted version on, the assemblies which are possibly not the latest).</p>
<p style="text-align: justify">We may not set &#8220;CopyLocal&#8221;=&#8221;False&#8221; on all the &#8220;file references&#8221; because MSTest needs a copy of those in the bin folder to be able to run the unit Tests (That would not be the case if we could find for MSTest an equivalent of the &#8220;ReferencePath&#8221; parameter of MSBuild).</p>
<p style="text-align: justify">We don&#8217;t have access to methods (or well described &#8220;algorithms&#8221;) to retrieve the exact list of assemblies part of the &#8220;primary output&#8221;. Such methods are only implemented in the Microsoft Setup Projects (Projects not supported, by the way, by MSBuild).</p>
<p style="text-align: justify">We don&#8217;t want all our developers to add MSBuild Scripts in their Visual Studio Projects to drop the &#8220;Targets&#8221; in the &#8220;Latest&#8221; folder.</p>
<p style="text-align: justify">Ex. copy &#8220;$(TargetDir)$(TargetName).???&#8221; &#8220;C:\RefAssemblies\Latest&#8221;</p>
<p style="text-align: justify">This is not only too error prone (like everything you request to a human developer), but it&#8217;s also not robust enough. It&#8217;s in our opinion impossible to maintain this with enough guarantee taking into account that developers can for example add support for new languages at any time. For each Project, in addition to the assembly $(TargetDir)$(TargetName).dll, we also have to drop the satellite assemblies (e.g.: &lt;culture&gt;\&lt;assemblyname&gt;.resources.dll&#8221;), etc&#8230;</p>
<p style="text-align: justify">The most generic solution we found to identify the assemblies part of the primary output, although quick and dirty, consists in parsing the FileListAbsolute.txt file generated by MSBuild itself and available in the &#8220;obj&#8221; folder. We &#8220;rely&#8221; so on direct output of Microsoft (the content of that file) and avoid to implement (and maintain) our own generic (and most probably complex) algorithm (&#8220;complex&#8221; because I have no idea how to detect satellite assemblies in a Visual Studio Project).</p>
<p style="text-align: justify">Notice: We may only drop the primary output of Builds in the &#8220;Latest&#8221; folder for &#8220;Continuous Integration&#8221; Builds or Builds targeting the Integration Environment (both using the latest version of the sources). Builds targeting Qualification, Pre-Production or Production use always a specific version of the sources instead of the latest version. Their purpose is indeed to fix a bug in the assemblies deployed in the targeted environment and build with older sources.</p>
<p style="text-align: justify"></div>
<p style="text-align: justify"><span class="collapseomatic " id="id69b523b8c7cc5"  tabindex="0" title="Click to Read More"    >Click to Read More</span><span id='swap-id69b523b8c7cc5'  class='colomat-swap' style='display:none;'>Click to Close</span><div id="target-id69b523b8c7cc5" class="collapseomatic_content ">
[csharp]
using System;<br />
using System.IO;<br />
using System.Linq;<br />
using System.Activities;<br />
using System.Reflection;<br />
using System.Diagnostics;<br />
using System.ComponentModel;<br />
using System.Collections.Generic;<br />
using Microsoft.TeamFoundation.Build.Client;<br />
using Microsoft.Build.Evaluation;</p>
<p>namespace AG.SCRM.TeamBuild.Activity<br />
{<br />
    /// &amp;lt;summary&amp;gt;<br />
    /// Collect Build&#8217;s Primary Output Items<br />
    /// &amp;lt;/summary&amp;gt;<br />
    [BuildActivity(HostEnvironmentOption.All)]
    public sealed class GetPrimayOutput : CodeActivity<br />
    {<br />
        /// &amp;lt;summary&amp;gt;<br />
        /// List of Build&#8217;s Primary Output Items<br />
        /// &amp;lt;/summary&amp;gt;<br />
        [RequiredArgument]
        public InOutArgument&amp;lt;List&amp;lt;FileInfo&amp;gt;&amp;gt; PrimaryOutputItems { get; set; }</p>
<p>        /// &amp;lt;summary&amp;gt;<br />
        /// Build&#8217;s Configuration Parameter<br />
        /// &amp;lt;/summary&amp;gt;<br />
        [RequiredArgument]
        public InArgument&amp;lt;string&amp;gt; Configuration { get; set; }</p>
<p>        /// &amp;lt;summary&amp;gt;<br />
        /// Build&#8217;s Platform Parameter<br />
        /// &amp;lt;/summary&amp;gt;<br />
        [RequiredArgument]
        public InArgument&amp;lt;string&amp;gt; Platform { get; set; }</p>
<p>        /// &amp;lt;summary&amp;gt;<br />
        /// Local path of Build&#8217;s project file<br />
        /// &amp;lt;/summary&amp;gt;<br />
        [RequiredArgument]
        public InArgument&amp;lt;string&amp;gt; LocalProject { get; set; }</p>
<p>        [RequiredArgument]
        public InArgument&amp;lt;string&amp;gt; OutDir { get; set; }</p>
<p>        /// &amp;lt;summary&amp;gt;<br />
        /// Collect Build&#8217;s Primary Output Items<br />
        /// &amp;lt;/summary&amp;gt;<br />
        /// &amp;lt;param name=&amp;quot;context&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;<br />
        protected override void Execute(CodeActivityContext context)<br />
        {<br />
            var fileListAbsolute = PrimaryOutputItems.Get(context);<br />
            var localProject = LocalProject.Get(context);<br />
            var configuration = Configuration.Get(context);<br />
            var platform = Platform.Get(context);</p>
<p>            // Default Configuration is &amp;quot;Debug&amp;quot;<br />
            if (string.IsNullOrEmpty(configuration)) configuration = &amp;quot;Debug&amp;quot;;</p>
<p>            // Initialize the list of Build&#8217;s Primary Output Items if required.<br />
            // Otherwise, add Build&#8217;s Primary Output Items to the provided list<br />
            // to possibly support a loop on all Visual Studio Solution files in<br />
            // Build&#8217;s<br />
            if (fileListAbsolute == null) fileListAbsolute = new List&amp;lt;FileInfo&amp;gt;();</p>
<p>            if (Path.GetExtension(localProject).Equals(&amp;quot;.sln&amp;quot;, StringComparison.InvariantCultureIgnoreCase))<br />
            {<br />
                // Parse the Visual Studio Solution file<br />
                SolutionParser sln = new SolutionParser(localProject);<br />
                string root = Path.GetDirectoryName(localProject);<br />
                foreach (SolutionProject project in sln.MSBuildProjects)<br />
                {<br />
                    localProject = Path.Combine(root, project.RelativePath);<br />
                    CollectOutputItems(context, fileListAbsolute, configuration, platform, localProject);<br />
                }<br />
            }<br />
            else<br />
            {<br />
                // Validate that the file is a Visual Studio Project<br />
                var projectCollection = new ProjectCollection();<br />
                try<br />
                {<br />
                    Project project = projectCollection.LoadProject(localProject);<br />
                    string projectDirectoryPath = Path.GetDirectoryName(localProject);<br />
                    CollectOutputItems(context, fileListAbsolute, configuration, platform, localProject);<br />
                }<br />
                catch (Exception ex)<br />
                {<br />
                    throw new Exception(string.Format(&amp;quot;Project file &#8216;{0}&#8217; is not a valid Visual Studio project.&amp;quot;, localProject), ex);<br />
                }<br />
                projectCollection.UnloadAllProjects();</p>
<p>            }</p>
<p>            context.SetValue(PrimaryOutputItems, fileListAbsolute);<br />
        }</p>
<p>        private static void CollectOutputItems(CodeActivityContext context, List&amp;lt;FileInfo&amp;gt; items, string configuration, string platform, string project)<br />
        {<br />
            string projectFileName = Path.GetFileName(project);<br />
            string projectName = Path.GetFileNameWithoutExtension(project);<br />
            string projectPath = Path.GetDirectoryName(project);<br />
            string fileListAbsolute = GetFileListAbsolute(configuration, platform, projectFileName, projectPath);</p>
<p>            if (!string.IsNullOrEmpty(fileListAbsolute))<br />
            {<br />
                System.IO.StreamReader file = null;<br />
                string line;</p>
<p>                string parent = Path.GetDirectoryName(fileListAbsolute);</p>
<p>                // Read the file and parse it line by line.<br />
                using (file = new System.IO.StreamReader(fileListAbsolute))<br />
                {<br />
                    while ((line = file.ReadLine()) != null)<br />
                    {<br />
                        // Ignore obj folder&#8217;s local items.<br />
                        if (!line.StartsWith(parent, StringComparison.OrdinalIgnoreCase))<br />
                        {<br />
                            FileInfo item = new FileInfo(line);<br />
                            if (item.Exists)<br />
                            {<br />
                                // We are actually only interested in .dll and .exe + their .pdb, .xml and .config<br />
                                if (item.Extension.Equals(&amp;quot;.dll&amp;quot;, StringComparison.OrdinalIgnoreCase) || item.Extension.Equals(&amp;quot;.exe&amp;quot;, StringComparison.OrdinalIgnoreCase))<br />
                                {<br />
                                    //MessageHelper.DisplayInformation(context, string.Format(&amp;quot;Build output of {0} contains: {1}.&amp;quot;, projectName, item.Name));<br />
                                    items.Add(item);</p>
<p>                                    var config = new FileInfo(Path.Combine(item.DirectoryName, item.Name + &amp;quot;.config&amp;quot;));<br />
                                    if (config.Exists)<br />
                                    {<br />
                                        //MessageHelper.DisplayInformation(context, string.Format(&amp;quot;Build output of {0} contains: {1}.&amp;quot;, projectName, config.Name));<br />
                                        items.Add(item);<br />
                                    }</p>
<p>                                    var pdb = new FileInfo(Path.Combine(item.DirectoryName, Path.GetFileNameWithoutExtension(item.FullName) + &amp;quot;.pdb&amp;quot;));<br />
                                    if (pdb.Exists)<br />
                                    {<br />
                                        items.Add(item);<br />
                                    }</p>
<p>                                    var xml = new FileInfo(Path.Combine(item.DirectoryName, Path.GetFileNameWithoutExtension(item.FullName) + &amp;quot;.xml&amp;quot;));<br />
                                    if (xml.Exists)<br />
                                    {<br />
                                        items.Add(item);<br />
                                    }<br />
                                }<br />
                            }<br />
                            else<br />
                            {<br />
                                //MessageHelper.DisplayWarning(context, string.Format(&amp;quot;Primary Output items not found for project {0}: {1}.&amp;quot;, projectName, line));<br />
                            }<br />
                        }<br />
                    }<br />
                }<br />
            }<br />
            else<br />
            {<br />
                //MessageHelper.DisplayWarning(context, string.Format(&amp;quot;SCRM: No FileListAbsolute found for project &#8216;{0}&#8217;&amp;quot;, projectName));<br />
            }<br />
        }</p>
<p>        /// &amp;lt;summary&amp;gt;<br />
        ///<br />
        /// &amp;lt;/summary&amp;gt;<br />
        /// &amp;lt;param name=&amp;quot;configuration&amp;quot;&amp;gt;Build&#8217;s Configuration: Debug or Release&amp;lt;/param&amp;gt;<br />
        /// &amp;lt;param name=&amp;quot;platform&amp;quot;&amp;gt;Build&#8217;s Target Platform: Any CPU or x86&amp;lt;/param&amp;gt;<br />
        /// &amp;lt;param name=&amp;quot;projectFileName&amp;quot;&amp;gt;Visual Studio Project filename&amp;lt;/param&amp;gt;<br />
        /// &amp;lt;param name=&amp;quot;projectPath&amp;quot;&amp;gt;Visual StudioProject path&amp;lt;/param&amp;gt;<br />
        /// &amp;lt;returns&amp;gt;The path of the FileListAbsolute.txt file.&amp;lt;/returns&amp;gt;<br />
        /// &amp;lt;remarks&amp;gt;This file should be located under /obj/{platform}/{configuration/}.<br />
        /// But we also check the parent folders if the file is not found where expected.<br />
        /// We did indeed experienced problem to locate this file for Builds with &amp;quot;Mixed Plateform&amp;quot; Target.&amp;lt;/remarks&amp;gt;<br />
        private static string GetFileListAbsolute(string configuration, string platform, string projectFileName, string projectPath)<br />
        {<br />
            var fileListAbsoluteName = projectFileName + &amp;quot;.FileListAbsolute.txt&amp;quot;;<br />
            var fileListAbsolutePath = Path.Combine(projectPath, &amp;quot;obj&amp;quot;, platform, configuration, fileListAbsoluteName);<br />
            if (!File.Exists(fileListAbsolutePath))<br />
            {<br />
                fileListAbsolutePath = Path.Combine(projectPath, &amp;quot;obj&amp;quot;, configuration, fileListAbsoluteName);<br />
                if (!File.Exists(fileListAbsolutePath))<br />
                {<br />
                    fileListAbsolutePath = Path.Combine(projectPath, &amp;quot;obj&amp;quot;, fileListAbsoluteName);<br />
                    if (!File.Exists(fileListAbsolutePath))<br />
                    {<br />
                        fileListAbsolutePath = null;<br />
                    }<br />
                }<br />
            }</p>
<p>            return fileListAbsolutePath;<br />
        }<br />
    }</p>
<p>    /// &amp;lt;summary&amp;gt;<br />
    /// This Visual Studio Solution file Parser can be used to retrieve lists of projects in a Solution.<br />
    /// The first list contains all projects that can be built with MSBuild.<br />
    /// The second list contains all the other projects.<br />
    /// &amp;lt;/summary&amp;gt;<br />
    /// &amp;lt;remarks&amp;gt;<br />
    /// Based on http://stackoverflow.com/questions/707107/library-for-parsing-visual-studio-solution-files.<br />
    /// It&#8217;s a wrapper on Microsoft Build&#8217;s internal class &amp;quot;SolutionParser&amp;quot;<br />
    /// &amp;lt;/remarks&amp;gt;<br />
    public class SolutionParser<br />
    {<br />
        static readonly Type s_SolutionParser;<br />
        static readonly PropertyInfo s_SolutionParser_solutionReader;<br />
        static readonly MethodInfo s_SolutionParser_parseSolution;<br />
        static readonly PropertyInfo s_SolutionParser_projects;</p>
<p>        public List&amp;lt;SolutionProject&amp;gt; MSBuildProjects { get; private set; }<br />
        public List&amp;lt;SolutionProject&amp;gt; OtherProjects { get; private set; }</p>
<p>        static SolutionParser()<br />
        {<br />
            s_SolutionParser = Type.GetType(&amp;quot;Microsoft.Build.Construction.SolutionParser, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&amp;quot;, false, false);<br />
            if (s_SolutionParser != null)<br />
            {<br />
                s_SolutionParser_solutionReader = s_SolutionParser.GetProperty(&amp;quot;SolutionReader&amp;quot;, BindingFlags.NonPublic | BindingFlags.Instance);<br />
                s_SolutionParser_projects = s_SolutionParser.GetProperty(&amp;quot;Projects&amp;quot;, BindingFlags.NonPublic | BindingFlags.Instance);<br />
                s_SolutionParser_parseSolution = s_SolutionParser.GetMethod(&amp;quot;ParseSolution&amp;quot;, BindingFlags.NonPublic | BindingFlags.Instance);<br />
            }<br />
        }</p>
<p>        public SolutionParser(string solutionFileName)<br />
        {<br />
            if (s_SolutionParser == null)<br />
            {<br />
                throw new InvalidOperationException(&amp;quot;Cannot find type &#8216;Microsoft.Build.Construction.SolutionParser&#8217; are you missing a assembly reference to &#8216;Microsoft.Build.dll&#8217;?&amp;quot;);<br />
            }<br />
            var solutionParser = s_SolutionParser.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First().Invoke(null);<br />
            using (var streamReader = new StreamReader(solutionFileName))<br />
            {<br />
                s_SolutionParser_solutionReader.SetValue(solutionParser, streamReader, null);<br />
                s_SolutionParser_parseSolution.Invoke(solutionParser, null);<br />
            }<br />
            MSBuildProjects = new List&amp;lt;SolutionProject&amp;gt;();<br />
            OtherProjects = new List&amp;lt;SolutionProject&amp;gt;();<br />
            var array = (Array)s_SolutionParser_projects.GetValue(solutionParser, null);<br />
            for (int i = 0; i &amp;lt; array.Length; i++)<br />
            {<br />
                SolutionProject project = new SolutionProject(array.GetValue(i));</p>
<p>                if (project.ProjectType == &amp;quot;KnownToBeMSBuildFormat&amp;quot;)<br />
                    MSBuildProjects.Add(project);<br />
                else<br />
                    OtherProjects.Add(project);<br />
            }<br />
        }<br />
    }</p>
<p>    /// &amp;lt;summary&amp;gt;<br />
    /// This class represent a Visual Studio Project member of a Solution.<br />
    /// &amp;lt;/summary&amp;gt;<br />
    /// &amp;lt;remarks&amp;gt;<br />
    /// It&#8217;s a wrapper on Microsoft Build&#8217;s internal class &amp;quot;ProjectInSolution&amp;quot;<br />
    /// &amp;lt;/remarks&amp;gt;<br />
    [DebuggerDisplay(&amp;quot;{ProjectName}, {RelativePath}, {ProjectGuid}, {ProjectType}&amp;quot;)]
    public class SolutionProject<br />
    {<br />
        static readonly Type s_ProjectInSolution;<br />
        static readonly PropertyInfo s_ProjectInSolution_ProjectName;<br />
        static readonly PropertyInfo s_ProjectInSolution_RelativePath;<br />
        static readonly PropertyInfo s_ProjectInSolution_ProjectGuid;<br />
        static readonly PropertyInfo s_ProjectInSolution_ProjectType;</p>
<p>        static SolutionProject()<br />
        {<br />
            s_ProjectInSolution = Type.GetType(&amp;quot;Microsoft.Build.Construction.ProjectInSolution, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&amp;quot;, false, false);<br />
            if (s_ProjectInSolution != null)<br />
            {<br />
                s_ProjectInSolution_ProjectName = s_ProjectInSolution.GetProperty(&amp;quot;ProjectName&amp;quot;, BindingFlags.NonPublic | BindingFlags.Instance);<br />
                s_ProjectInSolution_RelativePath = s_ProjectInSolution.GetProperty(&amp;quot;RelativePath&amp;quot;, BindingFlags.NonPublic | BindingFlags.Instance);<br />
                s_ProjectInSolution_ProjectGuid = s_ProjectInSolution.GetProperty(&amp;quot;ProjectGuid&amp;quot;, BindingFlags.NonPublic | BindingFlags.Instance);<br />
                s_ProjectInSolution_ProjectType = s_ProjectInSolution.GetProperty(&amp;quot;ProjectType&amp;quot;, BindingFlags.NonPublic | BindingFlags.Instance);<br />
            }<br />
        }</p>
<p>        public string ProjectName { get; private set; }<br />
        public string RelativePath { get; private set; }<br />
        public string ProjectGuid { get; private set; }<br />
        public string ProjectType { get; private set; }</p>
<p>        public SolutionProject(object solutionProject)<br />
        {<br />
            this.ProjectName = s_ProjectInSolution_ProjectName.GetValue(solutionProject, null) as string;<br />
            this.RelativePath = s_ProjectInSolution_RelativePath.GetValue(solutionProject, null) as string;<br />
            this.ProjectGuid = s_ProjectInSolution_ProjectGuid.GetValue(solutionProject, null) as string;<br />
            this.ProjectType = s_ProjectInSolution_ProjectType.GetValue(solutionProject, null).ToString();<br />
        }<br />
    }</p>
<p>    /// &amp;lt;summary&amp;gt;<br />
    /// List of known project type Guids from http://www.mztools.com/articles/2008/mz2008017.aspx<br />
    /// + BizTalk: http://winterdom.com/2008/12/biztalkserver2009msbuildtasks<br />
    /// + Workflow 4.0<br />
    /// &amp;lt;/summary&amp;gt;<br />
    public enum ProjectType<br />
    {<br />
        [Description(&amp;quot;{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}&amp;quot;)]
        Windows_CSharp,<br />
        [Description(&amp;quot;{F184B08F-C81C-45F6-A57F-5ABD9991F28F}&amp;quot;)]
        Windows_VBNET,<br />
        [Description(&amp;quot;{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}&amp;quot;)]
        Windows_VisualCpp,<br />
        [Description(&amp;quot;{349C5851-65DF-11DA-9384-00065B846F21}&amp;quot;)]
        Web_Application,<br />
        [Description(&amp;quot;{E24C65DC-7377-472B-9ABA-BC803B73C61A}&amp;quot;)]
        Web_Site,<br />
        [Description(&amp;quot;{F135691A-BF7E-435D-8960-F99683D2D49C}&amp;quot;)]
        Distributed_System,<br />
        [Description(&amp;quot;{3D9AD99F-2412-4246-B90B-4EAA41C64699}&amp;quot;)]
        Windows_Communication_Foundation_WCF,<br />
        [Description(&amp;quot;{60DC8134-EBA5-43B8-BCC9-BB4BC16C2548}&amp;quot;)]
        Windows_Presentation_Foundation_WPF,<br />
        [Description(&amp;quot;{C252FEB5-A946-4202-B1D4-9916A0590387}&amp;quot;)]
        Visual_Database_Tools,<br />
        [Description(&amp;quot;{A9ACE9BB-CECE-4E62-9AA4-C7E7C5BD2124}&amp;quot;)]
        Database,<br />
        [Description(&amp;quot;{4F174C21-8C12-11D0-8340-0000F80270F8}&amp;quot;)]
        Database_other_project_types,<br />
        [Description(&amp;quot;{3AC096D0-A1C2-E12C-1390-A8335801FDAB}&amp;quot;)]
        Test,<br />
        [Description(&amp;quot;{20D4826A-C6FA-45DB-90F4-C717570B9F32}&amp;quot;)]
        Legacy_2003_Smart_Device_CSharp,<br />
        [Description(&amp;quot;{CB4CE8C6-1BDB-4DC7-A4D3-65A1999772F8}&amp;quot;)]
        Legacy_2003_Smart_Device_VBNET,<br />
        [Description(&amp;quot;{4D628B5B-2FBC-4AA6-8C16-197242AEB884}&amp;quot;)]
        Smart_Device_CSharp,<br />
        [Description(&amp;quot;{68B1623D-7FB9-47D8-8664-7ECEA3297D4F}&amp;quot;)]
        Smart_Device_VBNET,<br />
        [Description(&amp;quot;{14822709-B5A1-4724-98CA-57A101D1B079}&amp;quot;)]
        Workflow_30_CSharp,<br />
        [Description(&amp;quot;{D59BE175-2ED0-4C54-BE3D-CDAA9F3214C8}&amp;quot;)]
        Workflow_30_VBNET,<br />
        [Description(&amp;quot;{06A35CCD-C46D-44D5-987B-CF40FF872267}&amp;quot;)]
        Deployment_Merge_Module,<br />
        [Description(&amp;quot;{3EA9E505-35AC-4774-B492-AD1749C4943A}&amp;quot;)]
        Deployment_Cab,<br />
        [Description(&amp;quot;{978C614F-708E-4E1A-B201-565925725DBA}&amp;quot;)]
        Deployment_Setup,<br />
        [Description(&amp;quot;{AB322303-2255-48EF-A496-5904EB18DA55}&amp;quot;)]
        Deployment_Smart_Device_Cab,<br />
        [Description(&amp;quot;{A860303F-1F3F-4691-B57E-529FC101A107}&amp;quot;)]
        Visual_Studio_Tools_for_Applications_VSTA,<br />
        [Description(&amp;quot;{BAA0C2D2-18E2-41B9-852F-F413020CAA33}&amp;quot;)]
        Visual_Studio_Tools_for_Office_VSTO,<br />
        [Description(&amp;quot;{F8810EC1-6754-47FC-A15F-DFABD2E3FA90}&amp;quot;)]
        SharePoint_Workflow,<br />
        [Description(&amp;quot;{6D335F3A-9D43-41b4-9D22-F6F17C4BE596}&amp;quot;)]
        XNA_Windows,<br />
        [Description(&amp;quot;{2DF5C3F4-5A5F-47a9-8E94-23B4456F55E2}&amp;quot;)]
        XNA_XBox,<br />
        [Description(&amp;quot;{D399B71A-8929-442a-A9AC-8BEC78BB2433}&amp;quot;)]
        XNA_Zune,<br />
        [Description(&amp;quot;{EC05E597-79D4-47f3-ADA0-324C4F7C7484}&amp;quot;)]
        SharePoint_VBNET,<br />
        [Description(&amp;quot;{593B0543-81F6-4436-BA1E-4747859CAAE2}&amp;quot;)]
        SharePoint_CSharp,<br />
        [Description(&amp;quot;{A1591282-1198-4647-A2B1-27E5FF5F6F3B}&amp;quot;)]
        Silverlight,<br />
        [Description(&amp;quot;EF7E3281-CD33-11D4-8326-00C04FA0CE8D&amp;quot;)]
        BizTalk,<br />
        [Description(&amp;quot;32f31d43-81cc-4c15-9de6-3fc5453562b6&amp;quot;)]
        Workflow_40<br />
    };</p>
<p>    /// &amp;lt;summary&amp;gt;<br />
    /// Helper Class to manage Visual Studio Project&#8217;s types<br />
    /// &amp;lt;/summary&amp;gt;<br />
    public static class ProjectTypeExtensions<br />
    {<br />
        public static Guid ToGuid(this ProjectType val)<br />
        {<br />
            DescriptionAttribute[] attributes = (DescriptionAttribute[])val.GetType().GetField(val.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);<br />
            return attributes.Length &amp;gt; 0 ? Guid.Parse(attributes[0].Description) : Guid.Empty;<br />
        }</p>
<p>        public static ProjectType Parse(string val)<br />
        {<br />
            return Parse(Guid.Parse(val));<br />
        }</p>
<p>        public static ProjectType Parse(Guid val)<br />
        {<br />
            ProjectType? type = null;<br />
            FieldInfo[] fis = typeof(ProjectType).GetFields();<br />
            foreach (FieldInfo fi in fis)<br />
            {<br />
                DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);<br />
                if (attributes.Length &amp;gt; 0)<br />
                {<br />
                    if (Guid.Parse(attributes[0].Description) == val)<br />
                    {<br />
                        if (Enum.IsDefined(typeof(ProjectType), fi.Name))<br />
                            type = (ProjectType)Enum.Parse(typeof(ProjectType), fi.Name);<br />
                        break;<br />
                    }<br />
                }<br />
            }<br />
            if (type.HasValue)<br />
                return type.Value;<br />
            else<br />
                throw new FormatException(string.Format(&amp;quot;'{0}&#8217; is not a valid Project Type&#8217;s Guid&amp;quot;, val.ToString()));<br />
        }</p>
<p>        public static List&amp;lt;ProjectType&amp;gt; GetMSBuildProjectTypes(string localProject)<br />
        {<br />
            var projectCollection = new ProjectCollection();<br />
            Project project;<br />
            try<br />
            {<br />
                project = projectCollection.LoadProject(localProject);<br />
            }<br />
            catch (Exception ex)<br />
            {<br />
                throw new Exception(string.Format(&amp;quot;Project Type cannot be determined as &#8216;{0}&#8217; is not a valid VS project.&amp;quot;, localProject), ex);<br />
            }</p>
<p>            var projectTypes = GetMSBuildProjectTypes(project);</p>
<p>            projectCollection.UnloadAllProjects();</p>
<p>            return projectTypes;<br />
        }</p>
<p>        public static List&amp;lt;ProjectType&amp;gt; GetMSBuildProjectTypes(Project project)<br />
        {<br />
            try<br />
            {<br />
                var projectTypeGuids = (from property in project.Properties<br />
                                        where property.Name == &amp;quot;ProjectTypeGuids&amp;quot;<br />
                                        select property.EvaluatedValue).FirstOrDefault();</p>
<p>                List&amp;lt;ProjectType&amp;gt; projectTypes;<br />
                if (string.IsNullOrEmpty(projectTypeGuids))<br />
                    projectTypes = new List&amp;lt;ProjectType&amp;gt;();<br />
                else<br />
                    projectTypes = (from guid in projectTypeGuids.Split(&#8216;;&#8217;) select Parse(guid)).ToList();</p>
<p>                return projectTypes;<br />
            }<br />
            catch (Exception ex)<br />
            {<br />
                throw new Exception(string.Format(&amp;quot;Unable to determine the project type of &#8216;{0}&#8217; due to: {1}&amp;quot;, Path.GetFileNameWithoutExtension(project.FullPath), ex.Message));<br />
            }<br />
        }<br />
    }<br />
}<br />
[/csharp]
<p style="text-align: justify"></div>
<div class="pvc_clear"></div>
<p id="pvc_stats_478" class="pvc_stats total_only  " data-element-id="478" style=""><i class="pvc-stats-icon medium" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" version="1.0" viewBox="0 0 502 315" preserveAspectRatio="xMidYMid meet"><g transform="translate(0,332) scale(0.1,-0.1)" fill="" stroke="none"><path d="M2394 3279 l-29 -30 -3 -207 c-2 -182 0 -211 15 -242 39 -76 157 -76 196 0 15 31 17 60 15 243 l-3 209 -33 29 c-26 23 -41 29 -80 29 -41 0 -53 -5 -78 -31z"/><path d="M3085 3251 c-45 -19 -58 -50 -96 -229 -47 -217 -49 -260 -13 -295 52 -53 146 -42 177 20 16 31 87 366 87 410 0 70 -86 122 -155 94z"/><path d="M1751 3234 c-13 -9 -29 -31 -37 -50 -12 -29 -10 -49 21 -204 19 -94 39 -189 45 -210 14 -50 54 -80 110 -80 34 0 48 6 76 34 21 21 34 44 34 59 0 14 -18 113 -40 219 -37 178 -43 195 -70 221 -36 32 -101 37 -139 11z"/><path d="M1163 3073 c-36 -7 -73 -59 -73 -102 0 -56 133 -378 171 -413 34 -32 83 -37 129 -13 70 36 67 87 -16 290 -86 209 -89 214 -129 231 -35 14 -42 15 -82 7z"/><path d="M3689 3066 c-15 -9 -33 -30 -42 -48 -48 -103 -147 -355 -147 -375 0 -98 131 -148 192 -74 13 15 57 108 97 206 80 196 84 226 37 273 -30 30 -99 39 -137 18z"/><path d="M583 2784 c-38 -19 -67 -74 -58 -113 9 -42 211 -354 242 -373 16 -10 45 -18 66 -18 51 0 107 52 107 100 0 39 -1 41 -124 234 -80 126 -108 162 -133 173 -41 17 -61 16 -100 -3z"/><path d="M4250 2784 c-14 -9 -74 -91 -133 -183 -95 -150 -107 -173 -107 -213 0 -55 33 -94 87 -104 67 -13 90 8 211 198 130 202 137 225 78 284 -27 27 -42 34 -72 34 -22 0 -50 -8 -64 -16z"/><path d="M2275 2693 c-553 -48 -1095 -270 -1585 -649 -135 -104 -459 -423 -483 -476 -23 -49 -22 -139 2 -186 73 -142 361 -457 571 -626 285 -228 642 -407 990 -497 242 -63 336 -73 660 -74 310 0 370 5 595 52 535 111 1045 392 1455 803 122 121 250 273 275 326 19 41 19 137 0 174 -41 79 -309 363 -465 492 -447 370 -946 591 -1479 653 -113 14 -422 18 -536 8z m395 -428 c171 -34 330 -124 456 -258 112 -119 167 -219 211 -378 27 -96 24 -300 -5 -401 -72 -255 -236 -447 -474 -557 -132 -62 -201 -76 -368 -76 -167 0 -236 14 -368 76 -213 98 -373 271 -451 485 -162 444 86 934 547 1084 153 49 292 57 452 25z m909 -232 c222 -123 408 -262 593 -441 76 -74 138 -139 138 -144 0 -16 -233 -242 -330 -319 -155 -123 -309 -223 -461 -299 l-81 -41 32 46 c18 26 49 83 70 128 143 306 141 649 -6 957 -25 52 -61 116 -79 142 l-34 47 45 -20 c26 -10 76 -36 113 -56z m-2057 25 c-40 -58 -105 -190 -130 -263 -110 -324 -59 -707 132 -981 25 -35 42 -64 37 -64 -19 0 -241 119 -326 174 -188 122 -406 314 -532 468 l-58 71 108 103 c185 178 428 349 672 473 66 33 121 60 123 61 2 0 -10 -19 -26 -42z"/><path d="M2375 1950 c-198 -44 -350 -190 -395 -379 -18 -76 -8 -221 19 -290 114 -284 457 -406 731 -260 98 52 188 154 231 260 27 69 37 214 19 290 -38 163 -166 304 -326 360 -67 23 -215 33 -279 19z"/></g></svg></i> <img decoding="async" width="16" height="16" alt="Loading" src="https://www.BeatificaBytes.be/wp-content/plugins/page-views-count/ajax-loader-2x.gif" border=0 /></p>
<div class="pvc_clear"></div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.BeatificaBytes.be/drop-the-primary-output-of-builds-in-a-latest-folder/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Target multiple environments with only one TFS Build Server</title>
		<link>https://www.BeatificaBytes.be/target-multiple-environments-with-only-one-tfs-build-server/</link>
					<comments>https://www.BeatificaBytes.be/target-multiple-environments-with-only-one-tfs-build-server/#respond</comments>
		
		<dc:creator><![CDATA[vletroye]]></dc:creator>
		<pubDate>Sun, 21 Oct 2012 18:05:24 +0000</pubDate>
				<category><![CDATA[TFS]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[MSBuild]]></category>
		<category><![CDATA[Team Build]]></category>
		<guid isPermaLink="false">/wordpress/?p=466</guid>

					<description><![CDATA[I had customize our Build Process Template to support multiple target environments on a single Build Machine. I.e.: to resolve the &#8220;file references&#8221; at Build [&#8230;]]]></description>
										<content:encoded><![CDATA[<p style="text-align: justify">I had customize our Build Process Template to support multiple target environments on a single Build Machine. I.e.: to resolve the &#8220;<em>file references</em>&#8221; at Build time depending on the environment targeted for the deployment.</p>
<p style="text-align: justify"><span class="collapseomatic " id="id69b523b8ca819"  tabindex="0" title="Click to Read More"    >Click to Read More</span><span id='swap-id69b523b8ca819'  class='colomat-swap' style='display:none;'>Click to Close</span><div id="target-id69b523b8ca819" class="collapseomatic_content ">
<div style="text-align: justify">At work, we have mainly four distinct environments: Integration, Qualification, Pre-Production and Production. Each application (and its referenced assemblies) are promoted from one environment to the next one via tasks (Release Distribution jobs) scheduled according to a predefined monthly Release Plan&#8230;</div>
<p style="text-align: justify">TFS Build Machines not only compile the applications to be deployed via the standard Release Distribution, but also the urgent fixes to be deployed directly in Pre-Production without passing through Integration and Qualification environments. It also happens, although really quite seldom, that a Build skips the Integration and goes directly to Qualification.</p>
<p style="text-align: justify">It&#8217;s also to be noticed that none of our applications (assemblies) are strong named and deployed in the GAC, neither on development workstations nor on servers. Instead, all referenced assemblies are always copied within the application&#8217;s bin folders, also on the servers.</p>
<p style="text-align: justify">Therefore, basically, we would need Build Machines dedicated for each target environment with the adequate assemblies made available on them, for reference resolution purpose. That would be a pity to have such Build Machines (and the related setup, maintenance, backup costs, &#8230;) for at most one build per month (Fix in Production and Qualification are fortunately not common).</p>
<p style="text-align: justify">To avoid that,  I did customize our Build Process Template to take a <em>Reference Path</em> as input and to pass it to MSBuild. Actually, when editing a Build Definition, the Builder can select the target Environment, and the Build will simply receive a path to the location containing the related assemblies.</p>
<p style="text-align: left">Ex.: MSBuild mySolution.sln /p:ReferencePath=&#8221;c:\RefAssemblies\Qualification\&#8221;</p>
<p style="text-align: justify">How can I be sure that this <em>Reference Path</em> won&#8217;t interfere with any <em>Hint Paths</em> defined in the Visual Studio projects?</p>
<p style="text-align: justify">First, note that the location provided to MSBuild via the &#8220;<em>ReferencePath</em>&#8221; parameter will be probed to resolve all &#8220;file references&#8221; before any other location on the standard probing path. But we also pay attention to not make the assemblies available on the Hint Path on the Build Machines:</p>
<ul>
<li>On Development Workstations, all our assemblies are made available in a single &#8220;<em>Reference Assemblies</em>&#8221; folder. Developers add references on assemblies in there for development and local testing purpose. They can also start a <em>task</em> at will to update this &#8220;<em>Reference Assemblies</em>&#8221; folder with the latest version of the assemblies (the versions used in the Integration Environment) or with the version currently deployed in the Qualification or Production Environments (e.g.: for bug fixing purpose).</li>
</ul>
<ul>
<li><span style="text-align: justify">On the Build Machines, there is one &#8220;</span><em>Reference Assemblies</em><span style="text-align: justify">&#8221; folder per environment (i.e.: updated by the Release Distribution with the assemblies currently in use in that environment). None of those folders is located at the same path as the &#8220;</span><em>Reference Assemblies</em><span style="text-align: justify">&#8221; folder of the Development Workstations. As a result, MSBuild cannot use the Hint Paths found in the Visual Studio projects to locate the referenced assemblies. Instead, it uses the path of the &#8220;</span><em>Reference Assemblies</em><span style="text-align: justify">&#8221; folder passed to it via its parameter /p:ReferencePath.</span></li>
</ul>
<p style="text-align: justify">In addition to the &#8220;Reference Assemblies&#8221; folders per environment, we also have one  extra folder containing the output of each latest successful Build. This one is used for &#8220;<em>Continuous Integration</em>&#8220;. No need to update the references in the Visual Studio Projects, MSBuild always find in that folder the latest version of each assembly recently built on any Build Machine (if requested to do so via the Build Definition). This is by the way the default &#8220;target environment&#8221; for all &#8220;Rolling Builds&#8221; defined on &#8220;Development Branches&#8221;, so any breaking features in a new version of a referenced assembly is immediately detected. Builds &#8220;<em>candidate</em>&#8221; to be promoted use by default the Reference Path with the assemblies from the <em>Integration</em> environment.</p>
<p style="text-align: justify"></div>
<div class="pvc_clear"></div>
<p id="pvc_stats_466" class="pvc_stats total_only  " data-element-id="466" style=""><i class="pvc-stats-icon medium" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" version="1.0" viewBox="0 0 502 315" preserveAspectRatio="xMidYMid meet"><g transform="translate(0,332) scale(0.1,-0.1)" fill="" stroke="none"><path d="M2394 3279 l-29 -30 -3 -207 c-2 -182 0 -211 15 -242 39 -76 157 -76 196 0 15 31 17 60 15 243 l-3 209 -33 29 c-26 23 -41 29 -80 29 -41 0 -53 -5 -78 -31z"/><path d="M3085 3251 c-45 -19 -58 -50 -96 -229 -47 -217 -49 -260 -13 -295 52 -53 146 -42 177 20 16 31 87 366 87 410 0 70 -86 122 -155 94z"/><path d="M1751 3234 c-13 -9 -29 -31 -37 -50 -12 -29 -10 -49 21 -204 19 -94 39 -189 45 -210 14 -50 54 -80 110 -80 34 0 48 6 76 34 21 21 34 44 34 59 0 14 -18 113 -40 219 -37 178 -43 195 -70 221 -36 32 -101 37 -139 11z"/><path d="M1163 3073 c-36 -7 -73 -59 -73 -102 0 -56 133 -378 171 -413 34 -32 83 -37 129 -13 70 36 67 87 -16 290 -86 209 -89 214 -129 231 -35 14 -42 15 -82 7z"/><path d="M3689 3066 c-15 -9 -33 -30 -42 -48 -48 -103 -147 -355 -147 -375 0 -98 131 -148 192 -74 13 15 57 108 97 206 80 196 84 226 37 273 -30 30 -99 39 -137 18z"/><path d="M583 2784 c-38 -19 -67 -74 -58 -113 9 -42 211 -354 242 -373 16 -10 45 -18 66 -18 51 0 107 52 107 100 0 39 -1 41 -124 234 -80 126 -108 162 -133 173 -41 17 -61 16 -100 -3z"/><path d="M4250 2784 c-14 -9 -74 -91 -133 -183 -95 -150 -107 -173 -107 -213 0 -55 33 -94 87 -104 67 -13 90 8 211 198 130 202 137 225 78 284 -27 27 -42 34 -72 34 -22 0 -50 -8 -64 -16z"/><path d="M2275 2693 c-553 -48 -1095 -270 -1585 -649 -135 -104 -459 -423 -483 -476 -23 -49 -22 -139 2 -186 73 -142 361 -457 571 -626 285 -228 642 -407 990 -497 242 -63 336 -73 660 -74 310 0 370 5 595 52 535 111 1045 392 1455 803 122 121 250 273 275 326 19 41 19 137 0 174 -41 79 -309 363 -465 492 -447 370 -946 591 -1479 653 -113 14 -422 18 -536 8z m395 -428 c171 -34 330 -124 456 -258 112 -119 167 -219 211 -378 27 -96 24 -300 -5 -401 -72 -255 -236 -447 -474 -557 -132 -62 -201 -76 -368 -76 -167 0 -236 14 -368 76 -213 98 -373 271 -451 485 -162 444 86 934 547 1084 153 49 292 57 452 25z m909 -232 c222 -123 408 -262 593 -441 76 -74 138 -139 138 -144 0 -16 -233 -242 -330 -319 -155 -123 -309 -223 -461 -299 l-81 -41 32 46 c18 26 49 83 70 128 143 306 141 649 -6 957 -25 52 -61 116 -79 142 l-34 47 45 -20 c26 -10 76 -36 113 -56z m-2057 25 c-40 -58 -105 -190 -130 -263 -110 -324 -59 -707 132 -981 25 -35 42 -64 37 -64 -19 0 -241 119 -326 174 -188 122 -406 314 -532 468 l-58 71 108 103 c185 178 428 349 672 473 66 33 121 60 123 61 2 0 -10 -19 -26 -42z"/><path d="M2375 1950 c-198 -44 -350 -190 -395 -379 -18 -76 -8 -221 19 -290 114 -284 457 -406 731 -260 98 52 188 154 231 260 27 69 37 214 19 290 -38 163 -166 304 -326 360 -67 23 -215 33 -279 19z"/></g></svg></i> <img decoding="async" width="16" height="16" alt="Loading" src="https://www.BeatificaBytes.be/wp-content/plugins/page-views-count/ajax-loader-2x.gif" border=0 /></p>
<div class="pvc_clear"></div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.BeatificaBytes.be/target-multiple-environments-with-only-one-tfs-build-server/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
