MSBuild: How to Future-Proof Import Project Path? - powershell

A similar question was asked a few years ago, but I'm wondering if anything has changed in the interim or if folks have new ideas how to do this.
I've imported MSBuildTasks (MSBuild Community Tasks) as a Nuget package into a project within my solution. I can define a property for the path to the .targets file as follows:
<PropertyGroup>
<MSBuildTasks>$(SolutionDir)Packages\MSBuildTasks.1.5.0.235\tools\MSBuild.Community.Tasks.Targets</MSBuildTasks>
</PropertyGroup>
... and then import it using:
<Import Project="$(MSBuildTasks)"/>
Of course, I may choose to update the package at a later date in which case the folder name changes, so I'd prefer to avoid hard-coding the version number. One way I thought of to avoid this was to have a powershell script look for the latest version:
function Find-PackagePath
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)]$packagesPath,
[Parameter(Position=1,Mandatory=1)]$packageName
)
return (Get-ChildItem ($packagesPath + "\" + $packageName + "*")).FullName | Sort-Object $_ | select -Last 1
}
... and inject that as a command-line property for MSBuild:
msbuild $solutionFile "/p:Configuration=$buildConfiguration;Platform=$buildPlatform;MSBuildTasks=$MSBuildTasks";
I can confirm with a message that the injected path is indeed transmitted to my target:
<Target Name="_ReportMSBuildTasksPath" BeforeTargets="_ComputeSemanticVersion">
<Message Text="MSBUILDTASKS = $(MSBuildTasks)"/>
</Target>
... but if I try to import using the same import statement above, I get the following error message:
The value "" of the "Project" attribute in element <Import> is invalid. Parameter "path" cannot have zero length.
This is where I run out of ideas. How can I avoid hard-coding the version number in the tools path?

I found it strange that you need to manually import something.
MSBuildTasks NuGet package includes build\MSBuildTasks.targets. And Visual Studio should automatically add import of this file into your .csproj file.
And this import path is maintained by NuGet Package Manager in the Visual Studio.
So, you should just be able to use the tasks you need without importing anything manually.
If it does not work, then please check that .csproj file really includes autogenerated import to proper .targets file mentioned above.

Related

Boxstarter fails to install package (extracted script is actually a zip file)

I'm trying to make a simple Boxstarter package that will install a few basics to new machines. Nothing special.
I've created a new package as suggested in the docs (using the Boxstarter shell):
New-BoxstarterPackage -Name MyPackage -Description "I hope you enjoy MyPackage"
I've ended up stripping everything I had in tools/ChocolateyInstall.ps1 away and now it just contains:
Write-ChocolateySuccess "A success message"
I've then packaged this with:
Invoke-BoxstarterBuild MyPackage
I've then copied the resulting MyPackage.1.0.0.nupkg file to a fresh machine that has Boxstarter installed on it and run with:
Install-BoxstarterPackage -PackageName "C:\Temp\MyPackage.1.0.0.nupkg"
This is when I see errors:
ERROR: At C:\ProgramData\chocolatey\lib\tmp4CEB.tmp\tools\ChocolateyInstall.ps1:2 char:647
+ ... ∟MyPackage.nuspec ¢↑( ¶uPKNÄ0♀Ý#q‡¨ˆ;lP&#Ø! ...
+ ~
Missing closing ')' in expression.
At C:\ProgramData\chocolatey\lib\tmp4CEB.tmp\tools\ChocolateyInstall.ps1:2 char:651
+ ... Package.nuspec ¢↑( ¶uPKNÄ0♀Ý#q‡¨ˆ;lP&#Ø!ħ,× ...
+ ~
The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quotation marks ("&") to pass it as part of a string.
If I open the version of ChocolateyInstall.ps1' from C:\ProgramData\Boxstarter\BuildPackages\tmp4CEB.tmp\tools`, it looks corrupt:
It also looks like it contains some XML.
What am I doing wrong?
I suspect that the issue that you are having here is that you are providing a path directly to a nupkg. As per the help documentation for the Install-BoxstarterPackagecmdlet, the PackageName property is expecting the following:
The names of one or more NuGet Packages to be installed or URIs or
file paths pointing to a Chocolatey script. If using package names,
the .nupkg file for the provided package names are searched in the
following locations and order:
.\BuildPackages relative to the parent directory of the module file
The Chocolatey community feed
NugetSources in Boxstarter.config when the 'DelegateChocoSources' switch is used
Can you please try by passing in the package name, using one of the suggested sources for the package?

VSTS - Version NuGet using AssemblyInfo and appending build number

I'm trying to set up a CI deployment for my NuGet package on VSTS so that when a new commit is made, a package is packed and sent to my feed. Unfortunately I'm not sure where to start; most of my experience with versioning has been manually updating a file that sits within the solution, hence this question, so if there is a better way to do this let me know.
I would like the name to be the version number in the AssemblyInfo.cs file ("0.0.1") with the build number of the automated build appended. So the final result would look something like "0.0.1.35".I would like to also avoid using date/time in my naming; a lot of the suggestions are to use this but I really wish to keep the version number clean so that I can release the packages.
I'm using the 'NuGet pack' task so I only have the options 'Use date-time', 'Use environment variable' or 'Use the build number'.
Date/time means I have to manually input a major, minor and patch which I would prefer to be automatic.
Environment variable, sounds like this could be it but I think I'm missing what I should put in this field.
I set my build name to be "$(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)"but not getting the result I hoped.
Any help would be greatly appreciated!
Do you have the desire to have the file version match the NuGet package version? If so, you can use the following solution.
By default, the NuGet pack command will use the file version as the Package Version. To use this functionality to get the expected output that you want, you will need to update the file version during the build. This can be done easily with the Update Assembly Info task from the VSTS marketplace. There are a number of other similar tasks, but this one allows you to only modify the revision part of the file version independently of the Major, Minor, and Build versions.
Add the Update Assembly Info task to your VSTS account
Modify your build definition and add the 'Update Assembly Info' task to the build. Ensure that it is before your Visual Studio Build or MSBuild Task as you need to change the assembly info before the build occurs
Set the values in the Update Assembly Task to match what you need for your assemblies. By default it sets Revision to $(Build.BuildId) which is what you want based on your requirements
Turn 'Automatic Package Versioning' off in the Nuget Pack task
Add the 'Update Assembly Info' task to you build process and ensure that it is before your Visual Studio or MSBuild task.
Your build should now create a Nugetpackage of 0.0.1.{Build.BuildId}
Note: this was tested with version 2.* of the NuGet Task and Version 2.* of Update Assembly info task.
The simple workflow is using environment variable:
Add new variable to build definition (e.g. packageVersion)
Add PowerShell task to get version in AssemblyInfo.cs (you can refer to the code in Use a PowerShell script to customize your build process)
Update variable value in PowerShell script (step 2) by calling Write-Host "##vso[task.setvariable variable= packageVersion;]xxx" (Logging Commands)
Add NuGet pack task (Automatic package versioning: Use an environment variable; Environment variable:packageVersion)
I wrote this PowerShell script to do that:
param
(
[parameter()][string] $FolderPath,
[parameter()][string] $FileExtension
)
$RegularExpression = [regex] 'AssemblyInformationalVersionAttribute\(\"(.*)\"\)'
$path = Get-Location
# Get the files from folder that ends in $FileExtension content
$assemblyInfoFile = (Get-ChildItem -Path $FolderPath -Force -Recurse -File -Include *$FileExtension).Name
# Get the Content of the file and store it in the variable
$fileContent = Get-Content $FolderPath/$assemblyInfoFile
foreach($content in $fileContent)
{
$match = [System.Text.RegularExpressions.Regex]::Match($content, $RegularExpression)
if($match.Success) {
$version = $match.groups[1].value
}
}
# Check if variable has content
if ($version)
{
Write-Host $version
Write-Host ##vso[task.setvariable variable=packageversion]$version
}
To run the script locally:
.\powershellScriptName.ps1 -FolderPath "c:\Git\" -FileExtension "AssemblyInfo.cs"
FolderPath: the path to output build solution
FileExtension: part of the name where we gonna search the version
VSTS steps:
Build a task to build the solution and save de output directory in a variable;
Add PowerShell task to call your script with FolderPath and FileExtension as parameters;
In the end, packageversion should have the correct version
** Project technology: .netcore

nuget tfs build 2015

I am trying to use NuGet to package and publish the package with TFS Build 2015 to local NuGet Server. I am getting error , I am not sure what am i missing. Thanks for Help.
Here is Error
Starting task: NuGet Packager
Set workingFolder to default: C:\Lucky\agent\tasks\NuGetPackager\0.1.58
Executing the powershell script: C:\Lucky\agent\tasks\NuGetPackager\0.1.58\NuGetPackager.ps1
Checking pattern is specified
No Pattern found in solution parameter.
Found files: 1
--File: "C:\Lucky\agent_work\1\s\Dev\FabrikamFiber.CallCenter"
The property DirectoryName does not exist or was not found.
Creating Nuget Arguments:
--ARGS: pack "C:\Lucky\agent_work\1\s\Dev\FabrikamFiber.CallCenter" -OutputDirectory "C:\Lucky\agent_work\1\s" -Properties Configuration=Release
Invoking nuget with pack "C:\Lucky\agent_work\1\s\Dev\FabrikamFiber.CallCenter" -OutputDirectory "C:\Lucky\agent_work\1\s" -Properties Configuration=Release on
C:\Lucky\agent\agent\worker\tools\NuGet.exe pack "C:\Lucky\agent_work\1\s\Dev\FabrikamFiber.CallCenter" -OutputDirectory "C:\Lucky\agent_work\1\s" -Properties Configuration=Release
MSBuild auto-detection: using msbuild version '14.0' from 'C:\Program Files (x86)\MSBuild\14.0\bin'.
Please specify a nuspec or project file to use.
Unexpected exit code 1 returned from tool NuGet.exe
Finishing task: NuGetPackager
Task NuGetPackager failed. This caused the job to fail. Look at the logs for the task for more details.
According to the error info:
Please specify a nuspec or project file to use. Unexpected exit code 1
returned from tool NuGet.exe
You may specified a wrong argument in nuget package task ,please double check you have followed below requirements:
Specify .csproj files (for example, **\*.csproj) for simple projects. In this case:
The packager compiles the .csproj files for packaging.
You must specify Configuration to Package (see below).
You do not have to check in a .nuspec file. If you do check one in, the packager honors its settings and replaces tokens such as $id$ and
$description$.
Specify .nuspec files (for example, **\*.nuspec) for more complex projects, such as multi-platform scenarios in which you need to
compile and package in separate steps. In this case:
The packager does not compile the .csproj files for packaging.
Each project is packaged only if it has a .nuspec file checked in.
The packager does not replace tokens in the .nuspec file (except the element, see Use build number to version package,
below). You must supply values for elements such as and
. The most common way to do this is to hardcode the
values in the .nuspec file.
Please double check your arguments , more details please refer this tutorial-- Pack NuGet packages.
Besides you could also enable verbose debug mode by adding system.debug=true to get a more detail build log info for troubleshooting.

NuGet - install.ps1 does not get called

I'm trying to create my first NuGet package. I don't know why my install.ps1 script does not get called. This is directory structure
--Package
|
- MyPackage.nuspec
- tools
|
- Install.ps1
- some_xml_file
I build package using this command line
nuget.exe pack MyPackage.nuspec
When I Install-Package from VS Package Manager Console install.ps1 does not get called.
I thought that maybe I had some errors in script and that's the reason so I commented out everything but
param($installPath, $toolsPath, $package, $project)
"ECHO"
But I don't see ECHO appearing in Package Manager Console. What can be wrong?
Install.ps will only be invoked if there is something in the \lib and/or \content folder, not for a "tools only" package, though. See here:
The package must have files in the content or lib folder for Install.ps1 to run. Just having something in the tools folder will not kick this off.
Use the Init.ps1 instead (however, this will be executed every time the solution is opened).
Install.ps1 (and Uninstall.ps1) are no longer called in v3, but you can use Init.ps1. See here:
Powershell script support was modified to no longer execute install
and uninstall scripts, but init scripts are still executed. Some of
the reasoning for this is the inability to determine which package
scripts need to be run when not all packages are directly referenced
by a project.
An alternative to the install script can sometimes be a package targets file. This targets file is automatically weaved into the project file (csproj, ...) and gets called with a build.
To allow Nuget to find this targets file and to weave it in, these two things are mandatory:
the name of the targets file must be <package-name>.targets
it must be saved in the folder build at the top level of the package
If you like to copy something to the output folder (e.g. some additional binaries, like native DLLs) you can put these binaries into the package under folder binaries and use this fragment in the targets file for the copying:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyBinaries" BeforeTargets="BeforeBuild">
<CreateItem Include="$(MSBuildThisFileDirectory)..\binaries\**\*.*">
<Output TaskParameter="Include" ItemName="PackageBinaries" />
</CreateItem>
<Copy SourceFiles="#(PackageBinaries)"
DestinationFolder="$(OutputPath)\%(RecursiveDir)"
SkipUnchangedFiles="true"
OverwriteReadOnlyFiles="true"
/>
</Target>
</Project>

NUnit assembly not found

I've used NUnit before, but not in a while, and never on this machine. I unzipped version 2.4.8 under Program Files, and I keep getting this error when trying to load my tests.
Could not load file or assembly 'nunit.framework, Version=2.4.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77' or one of its dependencies. The system cannot find the file specified**
In order to simplify the problem, I've compiled the most basic possible test file.
using NUnit.Framework;
namespace test
{
[TestFixture]
public class Tester
{
[Test]
public void ATest()
{
Assert.IsTrue(false, "At least the test ran!");
}
}
}
I've added "C:\Program Files\NUnit-2.4.8-net-2.0\bin" to my PATH (and rebooted). Note that if I copy the test assembly into that folder, then
C:\Program Files\NUnit-2.4.8-net-2.0\bin>nunit-console test.dll
works, but
C:\Program Files\NUnit-2.4.8-net-2.0\bin>nunit-console c:\dev\nunit_test\test.dll
and
C:\dev\nunit_test>nunit_console test.dll
fail with the above error.
Presumably I could get around this by copying the NUnit.Framework DLL file into my project's bin folder, but I don't remember having to do this in the past. Moreover, I get the same error in the GUI. Shouldn't the GUI know where the framework is located (that is, in the same folder)?
I'm not using Visual Studio. I use the following line to compile the test project.
%windir%\Microsoft.NET\Framework\v2.0.50727\csc.exe /r:"C:\Program Files\NUnit-2.4.8-net-2.0\bin\nunit.framework.dll" /t:library /out:test.dll test.cs
I tried both the .msi and the .zip file with the same result.
Make sure you have added a reference to nunit.framework. If you have, then make sure the properties of that reference have the copy local property set to true.
I had the same problem, and I had installed using NUnit-2.4.8-net-2.0.msi. Expanding on the "add to the GAC" comment, here's what I did:
Open your "Visual Studio command prompt (generally: make sure gacutil is in your path) and: cd "C:\Program Files\NUnit 2.4.8\bin"
Unregister your NUnit entries from the GAC. You can do this by finding the NUnit entries registered in the GAC:
gacutil /l | find /i "nunit" > temp.bat && notepad temp.bat
Prepend the nunit.core and nunit.framework lines with "gacutil /uf", i.e.:
gacutil /uf nunit.core,Version=2.4.2.0,Culture=neutral,PublicKeyToken=96d09a1eb7f44a77
gacutil /uf nunit.framework,Version=2.4.2.0,Culture=neutral,PublicKeyToken=96d09a1eb7f44a77
Run your .bat file to remove them:
temp.bat
Register the NUnit DLL files you need:
gacutil /i nunit.core.dll
gacutil /i nunit.framework.dll
If you install using NUnit-2.4.8-net-2.0.msi, the NUnit assemblies are added to the GAC.
You can also reinstall manually by running gacutil from the Visual Studio 2005 command prompt.
Note that the current NUnit installation (2.5.10) doesn't register itself automatically in the GAC.
If you must use GAC, register it via gacutil /i <nunitframeworkpath> where nunitframeworkpath is usually %Program Files%\NUnit\net-2.0\framework\nunit-framework.
I got this error message today when I tried to add a new test assembly to an existing NUnit test project. It seems that my test projects had multiple path references to identical nunit.framework.dll assemblies.
If you have more than one test assembly in your NUnit project, you may want to verify the Path property of the nunit.framework reference in your test projects. Once I made them match, the error message went away.