在构建后事件上更新本地 nuget 包
Posted
技术标签:
【中文标题】在构建后事件上更新本地 nuget 包【英文标题】:Updating local nuget package on post-build event 【发布时间】:2011-07-02 19:50:39 【问题描述】:我的本地 nuget 库存储库分别用于我的个人和工作相关类库。
我已经为不再开发的库创建了一些 nuget 包。我只为他们这样做,因为我不知道如何在我的项目构建后立即自动更新它们。
我发现所有工作都是通过带有 Visual Studio 命令提示符的 nuget 命令行完成的。所以我可以轻松地完成我需要的工作(当然我会完全了解命令而我不会!)
基本上,我希望在项目的构建后事件上执行以下任务。
关于项目构建:
-
将项目dll复制到特定文件夹(nuget包的lib文件夹)
为新文件版本更新 nuspec 文件(我的项目在每次构建时都增加文件版本)
使用新文件版本创建新的 nupkg 文件
Phil Haack 展示了其中的一些功能,但据我所知,它仍然是一个原型。
所以我的要求是以上。有其他人做到这一点吗?
【问题讨论】:
【参考方案1】:所选解决方案看起来可行,但似乎有更简单的解决方案可以满足您的要求。
您可以创建一个 nuspec 文件,该文件将从项目的元数据中读取数据。您只需使用此命令执行一次:
C:\<Path to project>\nuget spec
这会在规范文件中创建“令牌”,当您创建 nuget 包时,它将被项目的元数据替换。这包括文件版本。你会想要替换,因为从技术上讲,所有项目都应该拥有它们。
更多细节可以在这里找到:http://docs.nuget.org/docs/creating-packages/Creating-and-Publishing-a-Package#From_a_project
那么……
对于 .Net Framework(老式)项目,您可以在项目的 Post build 事件中执行以下操作:
nuget pack "$(ProjectPath)"
xcopy "$(TargetDir)*.nupkg" "<path where you are hosting your local nuget repo>" /C /Y
(假设 nuget.exe 在您的系统 PATH 中可用)。
对于 .Net Core 和标准项目,nuget 无法打包它们(请参阅 https://github.com/NuGet/Home/issues/4491)。相反,将此作为您的后期构建步骤:
dotnet pack "$(ProjectPath)" --no-build --include-source --include-symbols --output "<path where you are hosting your local nuget repo>"
当然,您可以调整选项以满足您的需求。有关dotnet pack
命令选项,请参阅https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-pack?tabs=netcore2x。
【讨论】:
如果要设置输出目录,也可以避免两步过程。此外,您可能需要考虑是否需要包含依赖项: nuget pack "$(ProjectPath)" -outputdirectory "c:\NuGetPackages" -IncludeReferencedProjects 这不适用于未将包路径公开为共享的远程 NuGet 提要。【参考方案2】:以防万一其他人(比如我)遇到这个古老的问题 - 在当前时代(VS2017,SDK/NugetReference 格式/.NET Core/.NET Standard/多目标项目),创建 NuGet 包是项目属性中的一个选项 - 因此,只需解决本地存储库的问题:
如果您有单目标项目,要将 .nupkg 文件复制到本地 NuGet 存储库,请添加构建后事件(项目属性 > 构建事件 > 构建后事件命令行):
xcopy $(TargetDir)*.nupkg [本地 nuget 存储库的路径] /s
喜欢:
xcopy $(TargetDir)*.nupkg G:\imbVelesOpenSource\LocalNuGet\imbVelesSecondGeneration\ /s
如果您有 多目标 项目,请将 .nupkg 文件复制到本地 NuGet 存储库: 添加构建后事件(项目属性>构建事件>构建后事件命令行):
xcopy $(TargetDir)..*.nupkg [本地 nuget 存储库的路径] /s
喜欢:
xcopy $(TargetDir)..*.nupkg G:\imbVelesOpenSource\LocalNuGet\imbVelesSecondGeneration\ /s
更新: 忘记构建后事件,有一种更简洁的方法(xcopy 方法对多目标项目很奇怪),只需将其添加到项目 XML 中即可:
<Target Name="CopyPackage" AfterTargets="Pack">
<Copy SourceFiles="$(OutputPath)$(PackageId).$(PackageVersion).nupkg" DestinationFolder="G:\imbVelesOpenSource\LocalNuGet\imbVelesSecondGeneration\" />
</Target>
更新
对于较新的 NuGet 版本,它切断了最后一个 0(来自 0.0.0.0 版本符号的补丁),您需要正则表达式 PackageVersion:
<Target Name="CopyPackage" AfterTargets="Pack">
<Copy SourceFiles="$(OutputPath)$(PackageId).$([System.Text.RegularExpressions.Regex]::Replace("$(PackageVersion)", "^(.+?)(\.0+)$", "$1")).nupkg" DestinationFolder="G:\imbVelesOpenSource\LocalNuGet\imbVelesSecondGeneration\" />
</Target>
【讨论】:
必须将我的目标修改为$(Package)
变量:nuget add bin\$(Configuration)\$(PackageId).$(PackageVersion).nupkg -source c:\packages
,您也可以在构建后部署到本地 Nuget 提要。 (确保选择“当构建更新项目输出时”)。
我跟随 okieh 和 Mike 并使用了以下内容(包括配置): Jeremy Skinner 写了a blog post,介绍了他如何执行包的自动构建并将它们上传到 NuGet 库。我认为它符合您的要求。
基本上,他使用 MsBuild 将版本(使用 MsBuild Community ExtensionsUpdateXml 任务)应用到 nuspec 文件并调用 nuget.exe 将其打包。
【讨论】:
【参考方案4】:我最近为此发布了一个解决方案,它实际上在构建期间创建/更新了 nuspec 文件,因此不必手动执行此操作,然后创建 nupkg 文件。
您只需要添加一个用于将包复制到其目的地的构建后事件(或将其作为可选阶段添加到我的解决方案中)。
您可以找到带有walk-through guide here 和source code + binary here 的文章。
【讨论】:
【参考方案5】:使用使用“PackageReference”标签的最新 nuget 包格式,您可以在 csproj 中使用以下简单的 postbuild 事件来更新具有最新依赖项的 nuspec 文件。
<Target Name="AfterBuild">
<WriteLinesToFile File="dependencies.xml" Overwrite="true" Lines=""/>
<WriteLinesToFile File="dependencies.xml" Overwrite="false" Lines="<dependencies>"/>
<WriteLinesToFile File="dependencies.xml" Overwrite="false" Lines="<dependency id="%(PackageReference.Identity)" version="%(PackageReference.Version)" />" />
<WriteLinesToFile File="dependencies.xml" Overwrite="false" Lines="</dependencies >"/>
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted -command "$xml = [xml] (Get-Content Project.nuspec); $xml.package.metadata.RemoveChild($xml.package.metadata.dependencies); $dependencies = [xml](Get-Content dependencies.xml); $xml.Package.Metadata.AppendChild($xml.ImportNode($dependencies.Dependencies, $true)); $xml.Save('Project.nuspec')""/>
<Delete Files="dependencies.xml" />
</Target>
唯一的前提是您有一个 nuspec 文件,其中包含项目目录中提到的其余元数据。这是一个示例 nuspec 文件:
<?xml version="1.0"?>
<package>
<metadata>
<id>Package Id</id>
<version>1.0.0</version>
<authors>Author name</authors>
<owners>Owner name</owners>
<description>Description</description>
<contentFiles>
<files include="**/content.zip" buildAction="None" copyToOutput="true" flatten="false" />
</contentFiles>
<dependencies>
</dependencies>
</metadata>
<files>
<file src="bin\Release\Project.dll" target="lib\net462" />
<file src="bin\Release\Project.pdb" target="lib\net462" />
<file src="bin\Release\file.zip" target="Content" />
</files>
</package>
【讨论】:
【参考方案6】:我通过命令行解决了这个问题 假设您已将 NuGet 的位置添加到路径环境或将稳定版本复制到给定目录(这就是我所做的)
我的 NuGet.exe 和证书位于名为 D:\Build 的文件夹中,您可能需要更新它以适应您的路径。
然后假设您有一个名为“CodeSignCertificate.pfx”的代码签名证书文件 带密码:pa$$w0rd
您可以从 Ascertia 以 17 欧元的价格获得一份简单的协同签名证书。他们还拥有有效期为 10 天的免费试用证书。链接https://account.ascertia.com/onlineCA/default
然后作为一个衬里我使用:
for %f in (X:\Packages\*.nupkg) do D:\Build\nuget sign %f -CertificatePath D:\Build\CodeSignCertificate.pfx -Timestamper http://timestamp.digicert.com -CertificatePassword pa$$w0rd
这会在我的输出目录中标记我所有的包
如果您只想签署最新的 NuGet 包,因为这可能是您刚刚编译的包,那么您可以使用类似的东西。
set Path="X:\ASP-WAF\DLL"
for /f "tokens=*" %%a in ('dir /A:-D /B /O:-D /S %Path%') do set NEW=%%a&& goto:n
:n
sign %NEW% -CertificatePath D:\Build\CodeSignCertificate.pfx -Timestamper http://timestamp.digicert.com -CertificatePassword pa$$w0rd
它不是单行的,但你可以将它放在一个 bat 文件中,然后在你的后期构建中调用它。
【讨论】:
以上是关于在构建后事件上更新本地 nuget 包的主要内容,如果未能解决你的问题,请参考以下文章
Docker在Linux上运行NetCore系列使用私有Nuget与多个本地包引用运行ASPNetCore
如何仅为调试构建运行 Visual Studio 构建后事件