Git Product home page Git Product logo

psbuild's Introduction

psbuild

Build status

The main purpose of this project to provide a better experience calling msbuild.exe from PowerShell. When using psbuild by default you'll get:

  • the latest version of msbuild.exe on your machine
  • multi-core build
  • log files, three formats: detailed, diagnostic and markdown
  • 32 bit version of msbuild.exe. Using the 64 bit version accidently can cause issues

It also simplifies passing in properties, targets by handling the work to translate PowerShell syntax to the call to msbuild.exe.

psbuild also has some functionality that you can use to create and edit MSBuild files from PowerShell.

To see the full set of commands that psbuild makes available just execute.

Get-Command -Module psbuild

Getting Started

download and install psbulid

(new-object Net.WebClient).DownloadString("https://raw.githubusercontent.com/ligershark/psbuild/master/src/GetPSBuild.ps1") | iex

build an msbuild file

Invoke-MSBuild C:\temp\msbuild\msbuild.proj

build a file and specify Configuration, Platform and VisualStudioVersion

psbuild has first class support for some well known properties. Configuration, Platform and VisualStudioVersion are just a few.

Invoke-MSBuild C:\temp\msbuild\msbuild.proj -configuration Release -platform 'Mixed Platforms' -visualStudioVersion 14.0

build a file passing arbitrary properties

To pass in properties that psbuild doesn't have first class support just use the -properties parameter.

Invoke-MSBuild C:\temp\msbuild\msbuild.proj -properties @{'MyProperty01'='myp1';'MyProperty02'='myp2'}

build an msbuild file and execute a specific target

Invoke-MSBuild C:\temp\msbuild\msbuild.proj -targets Demo

build an msbuild file and execute multiple targets

Invoke-MSBuild C:\temp\msbuild\msbuild.proj -targets Build,Demo

how to get the log file for the last build

When calling Invoke-MSBuild log files will be written by default in a temp folder. You can access those log files using the Open-PSBuildLog after the build completes. There are three log files by default: detailed, diagnostic and markdown.

PS> Invoke-MSBuild C:\temp\msbuild\proj1.proj
# returns the detailed log in the default editor
PS> Open-PSBuildLog

# returns the log in markdown format
PS> Open-PSBuildLog markdown

# returns the diagnostic
PS> Open-PSBuildLog diagnostic

how to open the log directory

To see logs from previous builds use the Open-PSBuildLogDirectory command. In this directory you'll find a folder for each project, each with log files.

How to pass extra arguments to msbuild.exe

When you call Invoke-MSBuild the call to msbuild.exe will be constructed for you. If you need to add additional arguments to msbuild.exe you can use the -extraArgs parameter. For example if you wanted to attach a custom logger or write a log file to a specific location.

Invoke-MSBuild C:\temp\msbuild\msbuild.proj -extraArgs '/flp3:v=d;logfile="C:\temp\msbuild\msbuild.detailed.log"'

show msbuild reserved properties

When authoring MSBuild files you'll often need to use some of MSBuild's reserved properties. You can either look this up on the web, or use psbuild to give you the info.

Get-MSBuildReservedProperties

This will display the list of known reserved properties and their values.

show common msbuild escape characters

When authoring MSBuild files there are a few special characters that you'll need to escape. Instead of searching the web for the result you can simply call this.

Get-MSBuildEscapeCharacters

You can also create a new MSBuild file with the following

When creating a new MSBuild file from scratch most people copy an existing one and remove the contents. psbuild offers a command to enable you to easily create a new empty MSBuild project file.

New-MSBuildProject -filePath C:\temp\msbuild\fromps.proj

to see what commands are available

Get-Command -Module psbuild

Most functions have help defined so you can use get-help on most commands for more details.

How to add psbuild to your build script.

If you're automating your build process then you should make sure they are portable. You can add the function below to your build script, and call it before using psbuild. If psbuild is not already installed it will be downloaded.

<#
.SYNOPSIS
    You can add this to you build script to ensure that psbuild is available before calling
    Invoke-MSBuild. If psbuild is not available locally it will be downloaded automatically.
#>
function EnsurePsbuildInstlled{
    [cmdletbinding()]
    param(
        [string]$psbuildInstallUri = 'https://raw.githubusercontent.com/ligershark/psbuild/master/src/GetPSBuild.ps1'
    )
    process{
        if(-not (Get-Command "Invoke-MsBuild" -errorAction SilentlyContinue)){
            'Installing psbuild from [{0}]' -f $psbuildInstallUri | Write-Verbose
            (new-object Net.WebClient).DownloadString($psbuildInstallUri) | iex
        }
        else{
            'psbuild already loaded, skipping download' | Write-Verbose
        }

        # make sure it's loaded and throw if not
        if(-not (Get-Command "Invoke-MsBuild" -errorAction SilentlyContinue)){
            throw ('Unable to install/load psbuild from [{0}]' -f $psbuildInstallUri)
        }
    }
}

Debug mode

In many cases after a build it would be helpful to be able to answer questions like the following.

  • What is the value of x property?
  • What is the value of y property?
  • What would the expression '@(Compile->'%(FullPath)') be?

But when you call msbuild.exe the project that is built is created in memory and trashed at the end of the process. Invoke-MSBuild now has a way that you can invoke your build and then have a "handle" to your project that was built. Using this object you can evaluate the properties and items. To enable this you just need to pass in the -debugMode switch to Invoke-MSBuild (Note: this is actively under development so if you run into an problems please open an issue). Here are some examples of what you can do.

PS> $bResult = Invoke-MSBuild .\temp.proj -debugMode

PS> $bResult.EvalProperty('someprop')
default

PS> $bResult.EvalItem('someitem')
temp.proj

PS> $bResult.ExpandString('$(someprop)')
default

PS> $bResult.ExpandString('@(someitem->''$(someprop)\%(Filename)%(Extension)'')')
default\temp.proj

You can get full access to the ProjectInstance object with the ProjectInstance property.

More functionality is available via the ProjectInstance object.

PS> $bResult.ProjectInstance.GetItems('someitem').EvaluatedInclude
temp.proj

You can get the BuildResuilt via the BuildResult parameter.

PS> $bResult.BuildResult.OverallResult
Failure

Reporting Issues

To report any issues please create an new item on the issues page.

Release Notes

  • Made psbuild self contained so that nothing needs to be downloaded at build time
  • Added Get-PSBuildVersion method
  • Update on how secrets are masked. The previous impl caused the users prompt to be modified.
  • Update to only add quotes when needed
  • Fixed an issue where commands were being quoted unnecessarily
  • Update to allow overriding settings with env variables https://github.com/ligershark/psbuild/commit/b00cc3c63a81c20f9101cbd111d1b1e1bffe874a
  • Update to ensure log directory is unique for every project built #71.
  • Update to filter secrets from log files. #59.
  • Added Import-FileReplacer to load file-replacer. This is a PowerShell module that can be used to replace text in files.
  • Added Import-NuGetPowershell to load nuget-powershell
  • Added a module manifest to support versioning #67
  • Added Open-PSBuildLogDirectory to open the log directory #66
  • Updated New-MSBuildProject to create files with the highest ToolsVersion on the box. Also added a -toolsVersion parameter.
  • Updated Invoke-MSBuild to not require targets when passing in -debugMode.
  • Added a function, Import-Pester, to get and load pester. If pester is not installed it will be downloaded. See #56.
  • Update to filter secrets in PowerShell output. When passing -password the value will automatically be masked. You can also add additional values to be masked. For more info see Get-Help Get-FilteredString or Get-Help Invoke-MSBuild -Examples. See #57.
  • Update to add entries to AppVeyor messages for projects that are built. See #56.
  • Updates to properly handle properties which have spaces. See #49.
  • Update to add -Platform as a paramter to Invoke-MSBuild
  • Added Invoke-CommandString which is used to call external .exe files. It is exported as well so can be used to simplify calling .exe files by users.
  • Added a parameter noLogFiles to Invoke-MSBuild which will disable writing log files. See #52.
  • Added psbuild alias for Invoke-MSBuild.
  • Added -bitness parameter to Invoke-MSBuild so that you can pick either 32 or 64 bit msbuild
  • Update to select 32 bit msbuild.exe when running Invoke-MSBuild
  • Update to throw an exception when the exit code from msbuild.exe is non-zero.
  • Update to add parameters to Open-PSBuildLog to specify the type of log to be opened.
  • Added a Markdown logger
  • Added -whatif support to Invoke-MSBuild

Contributing

Contributing is pretty simple. The project mostly consists of one .psm1 file located at /src/psbuild.psm1. You should send PRs to the dev branch. If it's a simple bug fix feel free to go ahead and submit the fix as a PR. If you have a feature please propose it in the issues section so that we can dicsuss your idea.

Credits

This project uses the following open source components.

psbuild's People

Contributors

dantup avatar dmitrylobanov avatar gep13 avatar rctycooner avatar sayedihashimi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

psbuild's Issues

Enable a debugMode switch

After building the project it would be nice if we could inspect the resulting project file. To facilitate this let's add a -debugMode switch to Invoke-MSBuild that will use the MSBuild APIs to invoke the build and then return the build result as well as resulting ProjectInstance.

Since we will be calling the APIs instead of the command line we may not be able to understand all the properties but known ones should be passed in.

Tasks

  • Add -debugMode switch
  • Pass in properties during build
  • Pass in targets during build
  • Attach console logger
  • Attach file loggers
  • Pass in max node count
  • Ability to set toolsversion
  • Create a parameter set on Invoke-MSBuild
  • Create helper functions (Eval-Property/Eval-Item/Expand-String) that act on the last build result
  • Add evaluation functions to simplify
  • Eval-Property
  • Eval-Item
  • Eval-String

Create nuget package

We should create a nuget package which can be used by other nuget packages to manipulate msbuild files.

Don't require a project to be passed

I currently have some PS functions like this:

Function Build { &'msbuild' /nologo /v:q }
Function Clean { &'msbuild' /t:Clean /nologo /v:q }

I was going to replace them with PSBuild; but it doesn't currently work without passing a project. With my functions, I can just type "build" in the root of my repo (which generally has a single .sln file), but PSBuild doesn't support this.

PSBuild should support the same; if I call Invoke-MSBuild with no project, call MSBuild anyway, and let it decide what to do.

Better Support for NuGet / Pkg Mgr Console

Better Support for NuGet / Pkg Mgr Console

We can have a better story around NuGet and the package manager console using psbuild. The following are some user statements.

  • As a nuget pkg author I can use psbuild to make it easier to manipulate MSBuild files. I can simply place a dependency on the psbuild nuget package then I can call the commands it makes available in my install.ps1/init.ps1.
  • As a dev I can use psbuild to make it easier to call msbuild from the pkg mgr console. Perhaps after installing the package we can automatically (or with an explicit command) install the module to the users machine and NuGet profile. That way they don't have to keep installing the nuget package if they don't want to. If the user has already installed psbuild as a module in his PS env. ideally that automatically lights up in the pkg manager console.
  • As a dev I can use psbuild from the pkg manager console to make it easier to interact with MSBuild files. I can create new msbuild files with a command, I can edit MSBuild files, etc.

-debugMode: Last build results functionality

When Invoke-MSBuild is called with -debugMode we should keep the last build result. When Invoke-MSBuild is called again (with or without -debugMode) we should re-set that value to either the new result or null.

After we save this value we can create the following cmdlets. These would be an alternative to assigning the result to a var and accessing via instance methods.

cmdlets / adv functions to create

  • Eval-MSBuildProp
  • Eval-MSBuildItem
  • Expand-MSBuildString
  • Get-MSBuildItems
  • Set-MSBuildProperty
  • Remove-MSBuildProperty
  • Remove-MSBuildItem
  • Save-MSBuildProject

Note: We should ensure that these are not confused with the existing "construction" related advanced functions.

We should be able to pipe the project to these cmdlets as well. Using the last build result should be the default.

Add support for /preprocess flag

We should add a parameter to Invoke-MSBuild for /preprocess. This could be helpful when working on MSBuild script inside of VS.

Add to psget

We should add psbuild to psget so that users can easily acquire psbuild.

Warning about msbuild location is displayed when -msbuildPath is used

If I specify
Invoke-MSBuild $slnFile -msbuildPath $msbuildPath -properties $msbuildProperties -Verbose

I should not see the following warning in my console, especially not in a different color:

Using msbuild.exe from [C:\Program Files (x86)\MSBuild\12.0\bin\amd64\msbuild.exe]. Use Set-MSBuild to change this.

-debugMode: Persist the ProjectInstance along with the log files.

When Invoke-MSBuild is called with the -debugMode flag at the end of the build we should save the resulting ProjectInstance to a file. We can use the log folder as the location to persist that file. We should perhaps have an options/parameter for that.

After persisting this to disk we should also keep track of this path in the buildResult object which is saved for later use.

Then we can create the following cmdlets / advanced functions

  • Get-PSBuildPostBuildResult (or something along those lines). The idea is that we would return the path to the .csproj file that contains the final "view" that MSBuild had for the project file. This would be really helpful for debugging.

This can be achieved with $projectInstance.ToProjectRootElement().Save('<path>')

Support special Platform parameter

Configuration can be set with a direct command-line parameter rather than through properties, presumably because it is in all sln/csproj files and usually needs to be specified for msbuild.

By the same logic, there should be such a Platform variable as well.

-debugMode: Enable executing targets after the initial build

When Invoke-MSBuild is called with the -debugMode flag we return the resulting ProjectInstance object. Users can use that object to then execute specific build targets. We could do the following to help here.

  • Add a function on the build result object to call build
  • Add a parameter to Invoke-MSBuild to accept a ProjectInstance (available only under -debugMode parameter set)

Add the ability to turn off logging

We should add the ability to turn off logging, both globally and for a single invocation of Invoke-MSBuild.

  • Add a switch -noLogFiles parameter to Invoke-MSBuild to avoid logging
  • Add a setting which turns logging off globally

Building .sln file using Invoke-MSBuild throws error

Invoking a sample console application .sln file using Invoke-MSBuild throws an error but compiles the project successfully and produces valid .exe.

Invoke-MSBuild .\ConsoleApplication.sln

Exception calling "Open" with "2" argument(s): "The project file could not be loaded. Data at the root level is
invalid. Line 2, position 1.  C:\.\ConsoleApplication.sln"
At C:\..\Modules\psbuild\psbuild.psm1:870 char:13
+             $project = ([Microsoft.Build.Construction.ProjectRootElement]::Open( ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : InvalidProjectFileException

Move appveyor config into repo

Since I was just learning appveyor I configured the build in the website directly. Now that I have everything configured I will move the config into appveyor.yml so that it's versioned with the code.

Add ParameterSets to Invoke-MSBuild

The user may have a few different intentions when calling Invoke-MSBuild.

  1. Build a file
  2. Build a file with -debugMode
  3. -preprocess

Each of these are mutually exclusive. We should add some parameter sets to Invoke-MSBuild to reflect this. The default parameter set should be Build a file.

Add markdown log

We should add support for generating a log that is written in markdown. Along with this change we should do a few more things, they are listed below.

  • Create a new markdown logger and update psbuild to use that
  • Improve how logs are written out. Today we create a detailed and a diagnostic log and its index based which one it is. Instead we should have named logs, and update Open-PSBiuldLog to have switches for which log should be opened.
  • Update acquisition experience to pull from nuget.org. Right now the GetPsBuild.ps1 script pulls from github. It would be better if this pulled from nuget.org instead. This will allow give us a lot of benefits like; versioning, easier testing, and some other stuff.
  • Update Open-PSBuildLog to support a switch for which type of log should be opened

Accept pipeline objects for Open-PSBuildLog cmdlet

Get-PSBuildLog returns one or more .log file and Open-PSBuildLog file opens the last .log file. One has to type two commands to open the log file. Can we have Open-PSBuildLog cmdlet accept pipeline object from Get-PSBuildLog.

Get-PSBuildLog | Open-PSBuildLog

With parameter defaults we can directly open the first log file just like it works right now.

Update test cases

The test cases are no longer current and are failing. We should make the following changes.

  • Update test cases so that they all pass
  • Update build.ps1 to execute the test cases
  • Update the CI build to execute test cases and fail if there is an error

Default Properties

When invoking msbuild.exe you can pass in parameters on the command line. These parameters are _overriding_ standard property declarations in the project file. In some cases it would be nice to be able to set the _default value_ for a property, i.e. the value that should be used if no other value has been specified. Since msbuild.exe doesn't support this we will have to build it ourselves.

User Experience

We should add a new parameter to the Invoke-MSBuild function that allows the user to pass in these properties. This property should be named defaultProperties.

Design

MSBuild doesn't have the concept of default properties but when MSBuild encounters a declaration like $(PropName) if the property has not been declared MSBuild will fall back to returning the value of an env var with the same name if it exists. We can exploit this behavior to implement default properties. Inside of Invoke-MSBuild before we call msbuild.exe we can set the default properties as env variables. If there is any clean up needed we can do that after msbuild.exe returns.

Open Items

  • If we set the properties as PS env vars will msbuild.exe be smart enough to pick those up?

how to create PublishProfile

please how to write :
msbuild MyProject.csproj /p:Configuration=Release /p:DeployOnBuild=true /p:PublishProfile=WMyProject

Run pester PS test cases in appveyor

We should make sure that the CI server executes the PowerShell test cases under the tests\ folder. We should wait for #38 to be completed. In addition to this we should update build.ps1 to execute the PS test cases. Perhaps we can add a parameter(s) to build.ps1 that just executes the test cases. That way we can use that both locally as well as in CI.

Add Filter-String, Write-Message and Get-Nuget to psbuild

I've used the functions below on several projects where psbuild is used. It would be easier to add this to the psbuild.psm1 directly.

Note: we should investigate if the names of the functions below are what we want to use

function Filter-String{
[cmdletbinding()]
    param(
        [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
        [string[]]$message
    )
    process{
        foreach($msg in $message){
            if($nugetApiKey){
                $msg = $msg.Replace($nugetApiKey,'REMOVED-FROM-LOG')
            }

            $msg
        }
    }
}

function Write-Message{
    [cmdletbinding()]
    param(
        [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
        [string[]]$message
    )
    process{
        Filter-String -message $message | Write-Verbose
    }
}

<#
.SYNOPSIS
    If nuget is in the tools
    folder then it will be downloaded there.
#>
function Get-Nuget{
    [cmdletbinding()]
    param(
        $toolsDir = ("$env:LOCALAPPDATA\LigerShark\tools\"),
        $nugetDownloadUrl = 'http://nuget.org/nuget.exe'
    )
    process{
        $nugetDestPath = Join-Path -Path $toolsDir -ChildPath nuget.exe

        if(!(Test-Path $nugetDestPath)){
            $nugetDir = ([System.IO.Path]::GetDirectoryName($nugetDestPath))
            if(!(Test-Path $nugetDir)){
                New-Item -Path $nugetDir -ItemType Directory | Out-Null
            }

            'Downloading nuget.exe' | Write-Message
            (New-Object System.Net.WebClient).DownloadFile($nugetDownloadUrl, $nugetDestPath)

            # double check that is was written to disk
            if(!(Test-Path $nugetDestPath)){
                throw 'unable to download nuget'
            }
        }

        # return the path of the file
        $nugetDestPath
    }
}

Arguments with spaces are not handled

$svnToolFolder = "C:\Program Files\TortoiseSVN\bin\"
$msbuildProperties = @{'SVNToolFolder'=$svnToolFolder;}
Invoke-MSBuild $slnFile -properties $msbuildProperties

As the point of the hashtable is to abstract away the command line, $svnToolFolder should automatically handle arguments with spaces. But this is what I see:

VERBOSE: Performing the operation "Invoke-MSBuild" on target "
msbuild.exe ..\Solutions\MySoliton.sln /p:SVNToolFolder=C:\Program Files\TortoiseSVN\bin\ [...]

Better support for appveyor

When building with psbuild you should get a better experience when using appveyor. For example.

  • Add appveyor msbuild logger
  • Build logs should be uploaded as build artifacts (off by default because it may contain sensitive data)
  • Write an appveyor message for each call to Invoke-MSBuild

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.