-
-
Notifications
You must be signed in to change notification settings - Fork 476
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[QUESTION] How (and why) does Pester package C# NuGet Packages? #1314
Comments
Possibly related, @mklement0 wrote this issue: PowerShell/PowerShell#6724 |
Hi,
Yes that is exactly the reason :)
Yes that is also true, it uses Gherkin that needs it as a dependency and is compiled against older .NET framework so it runs up to PowerShell v2. I think it is packaged this way because that is how choco package was packaged, and then someone asked for nuget package as well so they can use and manage it by VisualStudio when big VS and PowerShell tools were all the rage. Nuget and choco are pretty much the same thing, so the same package is pushed to both places. Since that time a lot have changed, but the package is still packaged the same way. Do you have any suggestions how to do it better? :) |
We're discussing it internally. We have four main ideas on how things can be done for developing large scale PowerShell projects. Before I explain those, understand that it is easier for us to higher productive C# engineers than IT people who know PowerShell and have business analyst-like mindset. ApproachesI've come up with 4 possible approaches, and given them all nicknames internally that I'll share here (emboldened), because it's hard to generate good ideas about best practices without giving back a little.
I guess there is a fifth style (that I've tried and liked, but found wanting more), which is @RamblingCookieMonster 's WFTools approach of a "dumb psd1 PowerShell Manifest file" that contains no information about what functions it exports (unless your build process dynamically builds the psd1 was well). The further downside of WFTools I've discovered (which is the real dealbreaker for me) is that the way it loads itself as a module causes really nasty stack traces where the line numbers are way off and hard to track down. |
@nohwnd So far, I've found the ".NET SDK-like" approach to be the most desirable approach. The downside is it creates an extra dll, the Dummy.dll for the Dummy.csproj class library. The other slightly annoying behavior is that if a Nuget package supports internationalization, dotnet publish will publish all satellite assemblies available. The other annoying problem is I'm not sure how to deal with "assembling binding redirect" hell. Our approach looks like this: <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net461;netstandard2.0</TargetFramework>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SomeNugetPackage" Version="2.11.0" /> // reference the concrete dll's in RequiredAssemblies psd1 key
<PackageReference Include="SomeOtherNugetPackage" Version="3.3.1" /> // reference the concrete dll's in RequiredAssemblies psd1 key
</ItemGroup>
<ItemGroup>
<Content Include="MyModule.psd1" CopyToPublishDirectory="PreserveNewest"/>
<Content Include="MyModule.psm1" CopyToPublishDirectory="PreserveNewest"/>
</ItemGroup>
</Project> In theory, this also allows targeting both PowerShell v5 and PowerShell Core. However, I don't think it can support older versions of .NET Framework like you mention Pester supporting .NET Framework 2 (is that even supported by Microsoft Premium Support contract?) Also, while theory is theory, in practice we discovered today that the lack of PowerShell's support for assemblyBinding redirect can also cause the need for hooking into the In theory, since psd1 is a walkable file format, it should even be possible to auto-generate the RequiredAssemblies from the deps.json file generated by MSBuild when it computes the transitive closure of all assemblies to generate the lock file. At the end of the day, the |
@nohwnd We made significant progress here:
So far, we have written a workstation/server reboot scheduler/executor/whatif utility, an ultrafast parallel system ping utility, and file share permissions auditing utility. I can not understate how much nicer this is than writing PowerShell directly for "system's engineering". |
@nohwnd One further improvement. Our launchSettings.json now looks like this: {
"profiles": {
"Debug Interactively": {
"commandName": "Executable",
"executablePath": "pwsh.exe",
// Note: $(TargetPath) is a built-in VS property referring to the project's output binary.
"commandLineArgs": "-noexit -command [console]::Title = 'Cmdlet Debugging - $(MSBuildProjectName)'; Import-Module -Verbose ('$(TargetPath)' -replace '[.]dll$', '.psd1')"
},
"Debug via Tests": {
"commandName": "Executable",
"executablePath": "pwsh.exe",
"commandLineArgs": "-NoExit -Command Import-Module ('$(TargetPath)' -replace '[.]dll$', '.psd1'); Set-Location '$(MSBuildProjectDirectory)/../$(MSBuildProjectName).Tests'; Invoke-Pester"
}
}
} This second profile target lets you open a powershell window, auto-invoke Invoke-Pester with your assembly under test, and then if you have to edit the ps1 pester tests (due to a bug in the tests), you can without needing to reload the Visual Studio debug session. The one limitation is it only lets you do one test assembly to one Binary Cmdlets assembly. Can you think of a better solution? |
Hi @dlwyatt
How (and why) does Pester package C# NuGet Packages the way it does?
We were looking at the most popular PSGallery packages, and, of course, your fantastic library is one of the most popular packages! We unzipped the raw nupkg and peeked inside to try to understand how you wrote your psd1 and how you were bundling your C# NuGet Packages like Newtonsoft.Json.dll and Gherkin.dll, but were surprised to see you don't declare these dependencies anywhere.
In fact, when I searched for
Add-Type
, I see a curious way of loading the Gherkin.dll I have not seen in anyone else's PowerShell code, and so I'm curious why you're callingAdd-Type
this way:Pester/Functions/Gherkin.ps1
Line 2 in 3e77d00
Add-Type
, and to ensure you're calling the "non-mocked" version ofAdd-Type
.Curiously, Newtonsoft.Json.dll doesn't appear to be loaded at all. Presumably, this is because you're using an older version of Gherkin.dll - but this doesn't really address my question, because ideally I want to load Nuget packages, not .NET assemblies, since they contain richer metadata than the assemblies themselves and are the actual artifact sources I want to include.
The text was updated successfully, but these errors were encountered: