Skip to content

Instantly share code, notes, and snippets.

@arlm
Forked from sayedihashimi/msbuild-feedback.md
Created September 28, 2016 12:26
Show Gist options
  • Save arlm/e1a6492c1b9de9ac809e243634c8f9b1 to your computer and use it in GitHub Desktop.
Save arlm/e1a6492c1b9de9ac809e243634c8f9b1 to your computer and use it in GitHub Desktop.
MSBuild feedback

MSBuild Feedback

This feedback is on the experience of using MSBuild, not just on msbuild.exe

Not in any order, I may sort them later.

Have people want to author scripts using MSBuild

Today creating and maintaining MSBuild scripts is challenging. Some of the challenges for the user include.

Creating an MSBuild file itself is challenging. Compare the hello world in MSBuild versus Gulp.

MSBuild

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="Demo">
    <Message Text="Hello world"/>
  </Target>
</Project>

Gulp

var gulp = require('gulp');
 
gulp.task('default', function() {
    console.log('Hello world.');
});

psake

task default {
    write-host 'hello world'
}

In the Gulp case once you spend some time with it you could easily type that in notepad. Since it's JavaScript there is good support for it in Visual Studio.

In the psake case, that one is easy to learn as well. There are good tools for PowerShell as well.

Imperative vs. Declarative

Being declarative has advantages, but it's also difficult for users to understand. When editing an MSBuild file you basically have to be aware of the world around you to correctly add functionality to an existing build. For example you may need to know; names of dependson properties, target names, property names, items names, etc.

In the imperative case you could just find the part of the script that you need to modify and party on it. Or add a call to your new method.

Help more with defaults

  • Release
  • bitness
  • help users pick the correct version of msbuild.exe
  • configuration
  • visualstudioversion
  • log to a file by default, for the case where users see an error scroll by with details but don't have it in the buffer after the build completes.

Support for "self bootstrapping"

MSBuild tasks are typically shipped in .dll files which users download from some website. It would be better if it was simpler to get 3rd party msbuild tasks or other tools. For example here is how you can create a self-bootstrapping msbuild script that calls nuget.exe.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="GetNuget">

  <!--
  This is an MSBuild snippet that can be used to download nuget to the path
  in the property NuGetExePath property.
  
  Usage:
   1. Import this file or copy and paste this into your build script
   2. Call the GetNuGet target before you use nuget.exe from $(NuGetExePath)
  -->
  
  <PropertyGroup>
    <NuGetExePath Condition=" '$(NuGetExePath)'=='' ">$(localappdata)\LigerShark\AzureJobs\tools\nuget.exe</NuGetExePath>
    <NuGetDownloadUrl Condition=" '$(NuGetDownloadUrl)'=='' ">http://nuget.org/nuget.exe</NuGetDownloadUrl>
  </PropertyGroup>
  
  <Target Name="GetNuget" Condition="!Exists('$(NuGetExePath)')">
    <Message Text="Downloading nuget from [$(NuGetDownloadUrl)] to [$(NuGetExePath)]" Importance="high"/>
    <ItemGroup>
      <_nugetexeitem Include="$(NuGetExePath)" />
    </ItemGroup>
    <MakeDir Directories="@(_nugetexeitem->'%(RootDir)%(Directory)')"/>
    <DownloadFile
        Address="$(NuGetDownloadUrl)"
        FileName="$(NuGetExePath)" />    
  </Target>

  <PropertyGroup Condition=" '$(ls-msbuildtasks-path)'=='' ">
    <ls-msbuildtasks-path>$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll</ls-msbuildtasks-path>
    <ls-msbuildtasks-path Condition=" !Exists('$(ls-msbuildtasks-path)')">$(MSBuildFrameworkToolsPath)\Microsoft.Build.Tasks.v4.0.dll</ls-msbuildtasks-path>
    <ls-msbuildtasks-path Condition=" !Exists('$(ls-msbuildtasks-path)')">$(windir)\Microsoft.NET\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll</ls-msbuildtasks-path>
  </PropertyGroup>
  
  <UsingTask TaskName="DownloadFile" TaskFactory="CodeTaskFactory" AssemblyFile="$(ls-msbuildtasks-path)">
    <!-- http://stackoverflow.com/a/12739168/105999 -->
    <ParameterGroup>
      <Address ParameterType="System.String" Required="true"/>
      <FileName ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Reference Include="System" />
      <Code Type="Fragment" Language="cs">
        <![CDATA[
            new System.Net.WebClient().DownloadFile(Address, FileName);
        ]]>
      </Code>
    </Task>
  </UsingTask>
  
</Project>

Latest at: https://gist.github.com/sayedihashimi/64736331b273162a1e76

It would be good if you could do this more easily for both taks and tools.

Have support for secrets

A lot of people have asked me questions like "how do I keep my passwords secure on a CI server". I'm not a security expert so I never have a really good answer for them. It would be nice for MSBuild to help here. Also sharing an MSBuild log with someone is a liability, you need to make sure there are no secrets in the log file before sharing. If MSBuild had a concept of secrets it could also ensure they were not printed in the logs.

Debugger support

Having a good debugging story if really needed when things go wrong. Being declarative makes this more difficult though IMO.

Good diagnostics

Easy to test

Make testing easy so that people can create reliable scripts, especially for cases where targets will be shared publically or with many people.

Allow users to interact with the project/build result after build completes

  • Evaluate properties
  • Evaluate items
  • Run targets
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment