I am building a project to be installed as a NuGet package and I want to set the properties of a SpecFlow feature file (because it is latest SpecFlow and should not produce code-behind files for the features.)
To achieve the effect of selecting a file, opening it's Properties pane and setting a couple of values, I have set my project structure like this:
\MyProject
\build
MyProject.targets
\Framework <the folder containing the file I want to affect>
FrameworkTests.feature <the file I want to affect>
\Framework
FrameworkTests.feature <the original location of the file I want to affect>
My .nuspec like this:
<?xml version="1.0"?>
<package >
<metadata minClientVersion="2.5">
<id>$id$</id>
<version>$version$</version>
...
</metadata>
<files>
<file src="build\MyProject.targets" target="build\MyProject.targets" />
<file src="build\FrameworkTests\FrameworkTests.feature" target="build\Framework\FrameworkTests.feature" />
</files>
</package>
My .targets file like this:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)FrameworkTests\FrameworkTests.feature">
<Link>FrameworkTests.feature</Link>
<CopyToOutputDirectory>Copy if newer</CopyToOutputDirectory>
<CustomToolNamespace></CustomToolNamespace>
</None>
</ItemGroup>
</Project>
I am not seeing the FrameworkTests.feature file get copied to the project when the package is installed. What do I need to change?
I am not seeing the FrameworkTests.feature file get copied to the project when the package is installed. What do I need to change?
This is the default behavior of the nuget folder conventions. If you set the file in the content
folder, nuget will copy those contents to the project root, then you will see them in the solution explorer. If you set files in the build
folder, nuget will automatically inserted them into the project file or project.lock.json
, like following script in the project file:
<Import Project="..\packages\MyProject.1.0.0\build\MyProject.targets" Condition="Exists('..\packages\MyProject.1.0.0\build\MyProject.targets')" />
So, this is the reason why you could not see the file FrameworkTests.feature
in the solution explorer unless you change the folder to content
.
You can refer to the document Creating the .nuspec file for more details:
Besides, if you change the folder to content, the .targets
would not work. Because when you change the folder to content, in the .targets
file, you need to change the path from:
<None Include="$(MSBuildThisFileDirectory)FrameworkTests\FrameworkTests.feature">
To:
<None Include="$(MSBuildThisFileDirectory)..\content\FrameworkTests\FrameworkTests.feature">
But MSBuild could not parse the path ..\content
. To resolve this issue, we need to change the .targets file to:
<None Include="$(ProjectDir)FrameworkTests.feature">
Alternatively, you can change property of files with Install.ps1
file, set it into the nuget package.
See this thread for more details.
Update:
I have also applied the changes you've described, but still cannot get the CopyToOutputDirectory file property to be updated.
Found it. There are two points you need update and one point should to know.
First point:
I found following script in your .nuspec
:
<files>
<file src="build\MyProject.targets" target="build\MyProject.targets" />
<file src="build\FrameworkTests\FrameworkTests.feature" target="build\Framework\FrameworkTests.feature" />
</files>
Note: You set your target folder for build\Framework
but in your .targets
file, you including it with FrameworkTests
;
<None Include="$(MSBuildThisFileDirectory)FrameworkTests\FrameworkTests.feature">
So, when change it to content folder, your .nuspec
file should be:
<files>
<file src="build\MyProject.targets" target="build\MyProject.targets" />
<file src="content\FrameworkTests\FrameworkTests.feature" target="content\FrameworkTests\FrameworkTests.feature" />
</files>
And the .targets
file should be:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="$(ProjectDir)FrameworkTests\FrameworkTests.feature">
<Link>FrameworkTests.feature</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CustomToolNamespace></CustomToolNamespace>
</None>
</ItemGroup>
</Project>
Second point need update:
The value of CopyToOutputDirectory
in the .targets
file should be PreserveNewest Not Copy if newer.
The point you need to know:
When you use this method to change the property of the FrameworkTests.feature
, the property of this file would not changed in the solution explorer, however, MSBuild will apply this change when you build the project. That because <Import Project="....\MyProject.targets" Condition="Exists('...')" />
will be parsed when you compile the project.
So, you can check the output for CopyToOutputDirectory
file property after build the project(After build your project, the file FrameworkTests.feature
would be copied to the output folder.)
Update2:
A lot of comments circulating that PowerShell scripts can't be run on build servers because the install command doesn't run them; Only VisualStudio will
Not sure of all the reasons why PowerShell scripts can't be run on build servers, but the vast majority are because PowerShell's default security level.
Try typing this in the PowerShell:
set-executionpolicy remotesigned
In the Visual Studio 2015, you need to install the extension PowerShell Tools for Visual Studio 2015 and the Windows Management Framework 4.0. After install them, the install.ps1 would works fine. Following is my .nuspec
file and install.ps
1 script.
.nuspec file:
<files>
<file src="content\FrameworkTests\FrameworkTests.feature" target="content\FrameworkTests\FrameworkTests.feature" />
<file src="scripts\Install.ps1" target="tools\Install.ps1" />
</files>
Note: Do not forget remove the MyProject.targets
in the .nuspec
file.
install.ps`1 script:
param($installPath, $toolsPath, $package, $project)
function MarkDirectoryAsCopyToOutputRecursive($item)
{
$item.ProjectItems | ForEach-Object { MarkFileASCopyToOutputDirectory($_) }
}
function MarkFileASCopyToOutputDirectory($item)
{
Try
{
Write-Host Try set $item.Name
$item.Properties.Item("CopyToOutputDirectory").Value = 2
}
Catch
{
Write-Host RecurseOn $item.Name
MarkDirectoryAsCopyToOutputRecursive($item)
}
}
#Now mark everything in the a directory as "Copy to newer"
MarkDirectoryAsCopyToOutputRecursive($project.ProjectItems.Item("FrameworkTests"))
Then, after install the nuget package, the property of the file FrameworkTests.feature would be changed to copy if newer
:
Hope this helps.