使用 AppVeyor 自动化 NuGet 包创建





5.00/5 (4投票s)
如何使用免费的持续构建服务 AppVeyor 来生成和发布 NuGet 包
我最近开源了一个.NET 库,但没有提供 NuGet 安装程序。在 Scott Hanselman 非常友好地为我的项目写了一篇博客文章后,我“被迫”提供了一个 :)
我以前从未发布过 NuGet 包。事实证明这非常容易。我想,对于其他处于类似情况的人来说,描述我是如何做到的会很有用。
基本上有三个步骤:
- 从 nuget.org 获取 API 密钥
- 创建 NuGet 包
- 发布您的包
获取 API 密钥
如果您还没有账户,请在 nuget.org 注册一个 NuGet 账户。如果您有 Microsoft 账户,可以使用该账户登录。
登录后,您的唯一 API 密钥会显示在您的账户详情旁边。它的格式类似于 GUID(例如:ABCDEF12-ABCD-ABCD-ABCD-ABCDEF123456
)。
请妥善保管此密钥!
创建 NuGet 包
NuGet 包包含两部分:元数据和安装文件。在本例中,我只有一个文件:MarkdownLog.dll
。
这是完成的 NuGet 包:
我正在使用出色的 NuGet Package Explorer 来显示其内容。
左侧窗格列出了元数据:名称、版本、版权信息——所有您期望的信息。
右侧窗格显示了包的内容。MarkdownLog.dll
是唯一需要安装的文件。它位于一个特殊命名的文件夹 portable-windows8+net45
中。此名称会告诉 NuGet 所需的 .NET 框架版本。
NuGet 包本身使用 nuget.exe 构建。我将 nuget.exe
下载到了我的项目的一个子文件夹 NuGet
中。所有与 NuGet 相关的都在这里。
为了创建包,NuGet 需要知道包含哪些文件和元数据。这在 .nuspec 文件中定义。
这是我使用的文件(在 GitHub 上查看):
<?xml version="1.0"?>
<package >
<metadata>
<id>MarkdownLog</id>
<version>$version$</version>
<authors>Stuart Wheelwright (@wheelies)</authors>
<licenseUrl>https://github.com/Wheelies/MarkdownLog/blob/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/Wheelies/MarkdownLog</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Lightweight .NET component for programmatically generating Markdown. Useful for producing rich diagnostic logs with minimal dependencies.</description>
<copyright>Copyright 2014 BlackJet Software Ltd</copyright>
<tags>markdown diagnostics logging pcl</tags>
</metadata>
<files>
<file src="..\MarkdownLog\bin\Release\MarkdownLog.dll" target="lib\portable-windows8+net45" />
</files>
</package>
此文件的内容应该是自明的,但如果您想深入了解,有全面的文档。
不过,我应该解释一下 $version$
部分。
我可以硬编码版本号(例如 0.9.0
),但那样的话,我将不得不手动将其与 DLL 中的版本号保持同步。
您会发现,当 MarkdownLog.dll
生成时,它会自动获得一个唯一的版本号,这是由自动构建系统生成的。
我使用出色的 AppVeyor 进行持续集成。每次有人将文件提交到项目的 GitHub 时,它都会自动构建、测试和打包项目的输出。该服务对开源项目是免费的,我强烈推荐它。
您可以通过两种方式配置 AppVeyor 中的项目构建:一种是使用其易于使用的 Web 界面,另一种是在 GitHub 存储库的根目录创建一个名为 appveyor.yml
的文件。我最初使用的是 Web 界面,但一旦一切正常工作并且我对它的工作原理感到满意后,就切换到了使用文件。将项目的构建配置保存在文件中意味着我可以比较修订版本,并在出现问题时回滚到早期版本。
完整的构建配置可以在 MarkdownLog 的 GitHub 存储库 中看到。这是自动将版本信息注入 DLL 的部分。
version: 0.9.0.{build}
assembly_info:
patch: true
file: AssemblyInfo.*
assembly_version: "{version}"
assembly_file_version: "{version}"
assembly_informational_version: "{version}"
{build}
是 AppVeyor 构建系统提供的自动递增数字。它用于创建完整的版本号(例如 0.9.0.23
),该版本号在 .NET 解决方案构建之前自动注入到 AssemblyInfo.cs 中。如果您查看 MarkdownLog.dll
的文件属性,您将看到最终结果。
appveyor.yml
构建配置的下一部分指定了要构建的 .NET 解决方案的名称。
build:
project: MarkdownLog.sln
如果 .NET 构建成功完成,将运行单元测试。如果测试通过,将执行一个名为 pack.ps1
的脚本。
after_test:
- ps: .\nuget\pack.ps1
pack.ps1
是一个简单的 PowerShell 脚本,用于创建 NuGet 包。
$root = (split-path -parent $MyInvocation.MyCommand.Definition) + '\..'
$version = [System.Reflection.Assembly]::LoadFile("$root\MarkdownLog\bin\Release\MarkdownLog.dll").GetName().Version
$versionStr = "{0}.{1}.{2}" -f ($version.Major, $version.Minor, $version.Build)
Write-Host "Setting .nuspec version tag to $versionStr"
$content = (Get-Content $root\NuGet\MarkdownLog.nuspec)
$content = $content -replace '\$version\$',$versionStr
$content | Out-File $root\nuget\MarkdownLog.compiled.nuspec
& $root\NuGet\NuGet.exe pack $root\nuget\MarkdownLog.compiled.nuspec
pack.ps1
脚本在很大程度上基于我在另一个 GitHub 项目中找到的这个脚本。
pack.ps1
和 MarkdownLog.nuspec
都位于 NuGet 文件夹中,与 nuget.exe
一起。
pack.ps1
中有趣的部分在最后,那里调用了 nuget pack
。此调用将使用注入了完整版本号的 .nuspec
文件副本来构建一个 .nupkg
文件。
每个构建都会创建一个 .nupkg
文件。您可以在 MarkdownLog 构件页面上看到一个示例。
发布您的包
流程的最后一步是最简单的。
现在我们有了 API 密钥和一个 .nupkg
文件,我们可以将它们组合起来,并将包发布到 NuGet.org。
如果我们手动执行此操作,我们会调用几个 NuGet 命令。
nuget setApiKey Your-API-Key
nuget push YourPackage.nupkg
要在 AppVeyor 中实现自动化,过程几乎一样简单,但有一个额外的步骤。我们首先需要加密我们的 API 密钥。然后可以将此加密版本公开,而无需暴露私钥。
AppVeyor 提供了一个在线工具来加密密钥。在框中输入您的私钥,然后单击“Encrypt”,您将获得一个可以像这样放在 appveyor.yml
构建配置文件中的密钥:
deploy:
provider: NuGet
api_key:
secure: n/2gZwCGLcoLBr5nGu5akS0IFQ1YHciI6Wz0NGC+1mLTUtO08Uy+TWn7OtyLG9v3
artifact: /.*\.nupkg/
AppVeyor 加密的 API 密钥版本放置在 secure
值中。artifact
值告诉 AppVeyor 在哪里可以找到包。我使用正则表达式匹配所有扩展名为 .nupkg
的文件。
就是这样。
当构建成功完成后,会自动创建一个 NuGet 包并发布到 NuGet.org。
但是,您可能不希望在存储库中的任何内容发生更改时都发布 NuGet 包。只发布包含经过充分测试的错误修复或新功能的包才是明智的;而不是每次在代码注释中修复一个错别字时都发布一个!
目前,我还没有一个好的解决方案。我目前通过注释掉/取消注释构建配置的部署部分来控制发布。我真的很想要一个更优雅的解决方案。我正在考虑的一个选项是创建一个新的 release
分支在 GitHub 中。此分支的构建会自动发布包,但普通的 dev
分支不会。要发布,我只需执行从 dev
到 release
的合并。
您有什么更好的建议吗?